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

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


当前回答

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

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

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

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

其他回答

基于@mkorpela的精彩回答,我写了一个类似的包(ipromise pypi github),它做了更多的检查:

假设A继承了B和C, B继承了C。

模块ipromise检查:

If A.f overrides B.f, B.f must exist, and A must inherit from B. (This is the check from the overrides package). You don't have the pattern A.f declares that it overrides B.f, which then declares that it overrides C.f. A should say that it overrides from C.f since B might decide to stop overriding this method, and that should not result in downstream updates. You don't have the pattern A.f declares that it overrides C.f, but B.f does not declare its override. You don't have the pattern A.f declares that it overrides C.f, but B.f declares that it overrides from some D.f.

它还具有用于标记和检查实现抽象方法的各种特性。

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

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

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

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

Hear是最简单的,可以在Jython下使用Java类:

class MyClass(SomeJavaClass):
     def __init__(self):
         setattr(self, "name_of_method_to_override", __method_override__)

     def __method_override__(self, some_args):
         some_thing_to_do()

这里是一个没有注释的不同解决方案。

它有一个稍微不同的目标。其他建议的解决方案检查给定的方法是否实际覆盖了父方法,而这个解决方案检查是否所有的父方法都被覆盖了。

你不必引发AssertionError,但可以打印警告或在生产环境中通过检查__init__中的env并在检查之前返回它。

class Parent:

    def a():
        pass

    def b():
        pass

class Child(Overrides, Parent):

    def a()

    # raises an error, as b() is not overridden


class Overrides:

    def __init__(self):
        # collect all defined methods of all base-classes
        bases = [b for b in self.__class__.__bases__ if b != Overrides]
        required_methods = set()
        for base in bases:
            required_methods = required_methods.union(set([f for f in dir(base) if not f.startswith('_')]))
        
        # check for each method in each base class (in required_methods)
        # if the class, that inherits `Overrides` implements them all
        missing = []
        # me is the fully qualified name of the CLASS, which inherits 
        # `Overrides`
        me = self.__class__.__qualname__
        for required_method in required_methods:

            # The method can be either defined in the parent or the child 
            # class. To check it, we get a reference to the method via 
            # getattr
            try:
                found = getattr(self, required_method)
            except AttributeError:
                # this should not happen, as getattr returns the method in 
                # the parent class if it is not defined in the cild class.
                # It has to be in a parent class, as the required_methods 
                # is a union of all base-class methods.
                missing.append(required_method)
                continue
            
            # here is, where the magic happens.
            # found is a reference to a method, and found.__qualname__ is
            # the full-name of the METHOD. Remember, that me is the full
            # name of the class. 
            # We want to check, where the method is defined. If it is 
            # defined in an parent class, we did no override it, thus it 
            # is missing. 
            # If we did not override, the __qualname__ is Parent.method
            # If we did override it, the __qualname__ is Child.method
            # With this fact, we can determine if the class, which uses
            # `Override` did implement it.
            if not found.__qualname__.startswith(me + '.'):
                missing.append(required_method)

        # Maybe a warning would be enough here
        if missing != []:
            raise AssertionError(f'{me} did not override these methods: {missing}')

即兴对@mkorpela的伟大回答,这里有一个版本

更精确的检查、命名和引发的Error对象

def overrides(interface_class):
    """
    Function override annotation.
    Corollary to @abc.abstractmethod where the override is not of an
    abstractmethod.
    Modified from answer https://stackoverflow.com/a/8313042/471376
    """
    def confirm_override(method):
        if method.__name__ not in dir(interface_class):
            raise NotImplementedError('function "%s" is an @override but that'
                                      ' function is not implemented in base'
                                      ' class %s'
                                      % (method.__name__,
                                         interface_class)
                                      )

        def func():
            pass

        attr = getattr(interface_class, method.__name__)
        if type(attr) is not type(func):
            raise NotImplementedError('function "%s" is an @override'
                                      ' but that is implemented as type %s'
                                      ' in base class %s, expected implemented'
                                      ' type %s'
                                      % (method.__name__,
                                         type(attr),
                                         interface_class,
                                         type(func))
                                      )
        return method
    return confirm_override

下面是它在实践中的样子:

NotImplementedError未在基类中实现

class A(object):
    # ERROR: `a` is not a implemented!
    pass

class B(A):
    @overrides(A)
    def a(self):
        pass

会导致更具有描述性的NotImplementedError错误

function "a" is an @override but that function is not implemented in base class <class '__main__.A'>

完整的堆栈

Traceback (most recent call last):
  …
  File "C:/Users/user1/project.py", line 135, in <module>
    class B(A):
  File "C:/Users/user1/project.py", line 136, in B
    @overrides(A)
  File "C:/Users/user1/project.py", line 110, in confirm_override
    interface_class)
NotImplementedError: function "a" is an @override but that function is not implemented in base class <class '__main__.A'>

NotImplementedError“期望实现的类型”

class A(object):
    # ERROR: `a` is not a function!
    a = ''

class B(A):
    @overrides(A)
    def a(self):
        pass

会导致更具有描述性的NotImplementedError错误

function "a" is an @override but that is implemented as type <class 'str'> in base class <class '__main__.A'>, expected implemented type <class 'function'>

完整的堆栈

Traceback (most recent call last):
  …
  File "C:/Users/user1/project.py", line 135, in <module>
    class B(A):
  File "C:/Users/user1/project.py", line 136, in B
    @overrides(A)
  File "C:/Users/user1/project.py", line 125, in confirm_override
    type(func))
NotImplementedError: function "a" is an @override but that is implemented as type <class 'str'> in base class <class '__main__.A'>, expected implemented type <class 'function'>


@mkorpela answer的伟大之处在于检查发生在初始化阶段。检查不需要“运行”。参考前面的例子,类B从未初始化(B()),但NotImplementedError仍然会引发。这意味着可以更快地捕获覆盖错误。