例如,在Java中,@Override注释不仅提供了重写的编译时检查,而且可以生成优秀的自文档代码。

我只是在寻找文档(尽管如果它是一些检查器(如pylint)的指示器,那是额外的奖励)。我可以在某处添加注释或文档字符串,但在Python中指示重写的惯用方法是什么?


当前回答

在Python 2.6+和Python 3.2+中,你可以这样做(实际上是模拟的,Python不支持函数重载,子类会自动覆盖父类的方法)。我们可以使用decorator。但首先,请注意Python的@decorators和Java的@Annotations是完全不同的东西。前一个是带有具体代码的包装器,后一个是编译器的标志。

为此,首先执行pip安装multipledispatch

from multipledispatch import dispatch as Override
# using alias 'Override' just to give you some feel :)

class A:
    def foo(self):
        print('foo in A')

    # More methods here


class B(A):
    @Override()
    def foo(self):
        print('foo in B')
    
    @Override(int)
    def foo(self,a):
        print('foo in B; arg =',a)
        
    @Override(str,float)
    def foo(self,a,b):
        print('foo in B; arg =',(a,b))
        
a=A()
b=B()
a.foo()
b.foo()
b.foo(4)
b.foo('Wheee',3.14)

输出:

foo in A
foo in B
foo in B; arg = 4
foo in B; arg = ('Wheee', 3.14)

注意,这里必须使用带有括号的decorator

需要记住的一件事是,由于Python没有直接的函数重载,所以即使类B没有继承自类A,但需要所有这些foo,也需要使用@Override(尽管在这种情况下使用别名'Overload'会更好看)

其他回答

Python不是Java。当然,没有真正的编译时检查。

我认为文档字符串中的注释就足够了。这允许您的方法的任何用户输入help(obj.method),并看到该方法是一个覆盖。

你也可以用类Foo(interface)显式地扩展一个接口,这将允许用户输入help(interface .method)来了解你的方法想要提供的功能。

在python 3.6及以上版本中,@override提供的功能可以使用python的描述符协议轻松实现,即set_name dunder方法:

class override:
    def __init__(self, func):
       self._func = func
       update_wrapper(self, func)

    def __get__(self, obj, obj_type):
        if obj is None:
            return self
        return self._func

    def __set_name__(self, obj_type, name):
        self.validate_override(obj_type, name)

    def validate_override(self, obj_type, name):
        for parent in obj_type.__bases__:
            func = parent.__dict__.get(name, None)
            if callable(func):
                return
        else:
            raise NotImplementedError(f"{obj_type.__name__} does not override {name}")

注意,这里的set_name是在定义包装类之后调用的,我们可以通过调用包装类的dunder方法基来获得它的父类。

对于它的父类,我们希望检查包装的函数是否在类中通过实现

检查函数名是否在类字典中 它是可调用的


使用i就像这样简单:

class AbstractShoppingCartService:
    def add_item(self, request: AddItemRequest) -> Cart:
        ...


class ShoppingCartService(AbstractShoppingCartService):
    @override
    def add_item(self, request: AddItemRequest) -> Cart:
        ...

如果你只是为了文档的目的,你可以定义你自己的覆盖装饰器:

def override(f):
    return f


class MyClass (BaseClass):

    @override
    def method(self):
        pass

这实际上只是花瓶,除非你创建override(f)的方式实际上是检查重写。

但是,这是Python,为什么要写成Java呢?

就像其他人说的,不像Java,没有@Overide标签,但是上面你可以使用装饰器创建自己的,但是我建议使用getattrib()全局方法,而不是使用内部dict,这样你就会得到如下内容:

def Override(superClass):
    def method(func)
        getattr(superClass,method.__name__)
    return method

如果你想,你可以在你自己的try catch中捕获getattr(),但我认为getattr方法在这种情况下更好。

此外,它还捕获绑定到类的所有项,包括类方法和变量

基于这个和fwc:s的答案,我创建了一个pip可安装包https://github.com/mkorpela/overrides

我经常在这里看到这个问题。 这主要发生在(再次)在我们的代码库中看到相同的错误之后:有人在重命名“接口”中的方法时忘记了一些“接口”实现类。

好吧,Python不是Java,但Python有强大的功能——显式比隐式好——在现实世界中,有一些真实的具体案例,这个东西会帮助我。

这是overrides decorator的草图。这将检查作为参数给出的类是否与被修饰的方法具有相同的方法(或其他东西)名称。

如果你能想到一个更好的解决方案,请张贴在这里!

def overrides(interface_class):
    def overrider(method):
        assert(method.__name__ in dir(interface_class))
        return method
    return overrider

其工作原理如下:

class MySuperInterface(object):
    def my_method(self):
        print 'hello world!'


class ConcreteImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def my_method(self):
        print 'hello kitty!'

如果你做了一个错误的版本,它会在类加载时引发一个断言错误:

class ConcreteFaultyImplementer(MySuperInterface):
    @overrides(MySuperInterface)
    def your_method(self):
        print 'bye bye!'

>> AssertionError!!!!!!!