以 Java 为例, @Override 注释不仅提供了重写的编译时检查,而且还提供了优秀的自记录代码。

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

有帮助吗?

解决方案

<强> UPDATE(2015年5月23日):在此基础上和FWC:的回答我创建画中画安装包的https:// github上的.com / mkorpela /覆盖

从我不时会在这里结束看这个问题。 主要发生这种情况之后(再次)看到在我们的代码库相同的错误:有人已经忘记了一些“接口”实现类而在“界面”重命名的方法..

好了Python是不是Java,但是Python有力量 - 和明确优于隐式 - 和有真正的具体案例在现实世界里,这个东西会帮助我

因此,这里是重写装饰的草图。这将检查作为参数的类具有与被装饰的方法相同的方法(或其它)的名称。

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

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!!!!!!!

其他提示

下面是不需要interface_class名称的规范的实现。

import inspect
import re

def overrides(method):
    # actually can't do this because a method is really just a function while inside a class def'n  
    #assert(inspect.ismethod(method))

    stack = inspect.stack()
    base_classes = re.search(r'class.+\((.+)\)\s*\:', stack[2][4][0]).group(1)

    # handle multiple inheritance
    base_classes = [s.strip() for s in base_classes.split(',')]
    if not base_classes:
        raise ValueError('overrides decorator: unable to determine base class') 

    # stack[0]=overrides, stack[1]=inside class def'n, stack[2]=outside class def'n
    derived_class_locals = stack[2][0].f_locals

    # replace each class name in base_classes with the actual class type
    for i, base_class in enumerate(base_classes):

        if '.' not in base_class:
            base_classes[i] = derived_class_locals[base_class]

        else:
            components = base_class.split('.')

            # obj is either a module or a class
            obj = derived_class_locals[components[0]]

            for c in components[1:]:
                assert(inspect.ismodule(obj) or inspect.isclass(obj))
                obj = getattr(obj, c)

            base_classes[i] = obj


    assert( any( hasattr(cls, method.__name__) for cls in base_classes ) )
    return method

如果你只是想为这个文件的目的,你可以定义自己的覆盖装饰:

def override(f):
    return f


class MyClass (BaseClass):

    @override
    def method(self):
        pass

这是真的只是养眼,除非你创建倍率(F)以这样的方式,实际上是检查覆盖。

不过,这是Python的,为什么写它喜欢它是Java的?

Python是不是Java。有,当然没有这样的事情真的像编译时检查。

我觉得在文档字符串评论充足。这使您的法键入help(obj.method)看,该方法是一个覆盖的任何用户。

您也可以明确地扩展与class Foo(Interface)的接口,这将允许用户键入help(Interface.method)获得有关你的方法旨在提供的功能的想法。

像其他人不同的Java说,没有@Overide标签上方。然而你却可以创建自己使用的装饰让你得到像下面我会建议使用getattrib()全局法,而不是使用内部字典:

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

如果你想,你可以在自己的尝试捕捉赶上GETATTR()提出自己的错误,但我认为GETATTR方法是在这种情况下更好。

同样在此捕获结合于包括类方法和vairables

的一类的所有项

即兴的@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答案伟大的事情是在一些初始化阶段的检查情况。检测并不需要“跑”。参照以前的例子中,class B从未初始化(B())尚NotImplementedError仍会提高。这意味着overrides错误越早捕获。

基于 @mkorpela 的精彩回答,我写了一个类似的包(我保证 皮皮 github)执行更多检查:

假设A继承自B和C。并且B继承自C。ipromise 检查

  • 如果A.f覆盖B.f,则B.f必须存在,并且A必须继承自B。(这是来自覆盖包的检查)。

  • 您没有模式 A.f 声明它覆盖 B.f,然后 B.f 声明它覆盖 C.f A 应该说它覆盖 C.f,因为 B 可能决定停止覆盖此方法,并且这不应导致下游更新。

  • 您没有模式 A.f 声明它覆盖 C.f,但 B.f 没有声明它的覆盖。

  • 您没有模式 A.f 声明它覆盖 C.f,但 B.f 声明它覆盖某些 D.f。

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

听到的是最简单的和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()
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top