在Python中,如何指示重写方法?

2024-05-23 22:38:38 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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


Tags: 方法代码文档地方java指示器pylintdocstring
3条回答

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

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

好吧,Python不是Java,但Python有强大的功能——显式比隐式更好——而且在现实世界中确实有一些具体的例子可以帮助我。

这里是覆盖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!!!!!!!

如果您只想用于文档目的,可以定义自己的重写装饰器:

def override(f):
    return f


class MyClass (BaseClass):

    @override
    def method(self):
        pass

这真的只是一个视觉糖果,除非您创建覆盖(f)的方式实际上是检查覆盖。

但是,这是Python,为什么要像编写Java一样编写它呢?

这里的实现不需要指定接口的类名。

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

相关问题 更多 >