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

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


当前回答

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()

其他回答

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

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

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

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

def override(f):
    return f


class MyClass (BaseClass):

    @override
    def method(self):
        pass

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

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

在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:
        ...

基于这个和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!!!!!!!

基于@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.

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