在Python中,如何表示我正在重写一个方法?

266 投票
14 回答
156610 浏览
提问于 2025-04-15 13:05

在Java中,比如说,@Override这个标记不仅可以在编译时检查你是否正确地覆盖了一个方法,还能让代码更容易理解,像是给代码加了注释一样。

我现在想找一些文档(虽然如果它能被像pylint这样的检查工具识别,那就更好了)。我可以在某个地方加个注释或者文档字符串,但在Python中,表示覆盖的方法的标准做法是什么呢?

14 个回答

31

这里有一个实现方法,不需要指定接口类的名称。

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
40

从Python 3.12开始(预计在2023年秋季发布),这项功能可以实现。我建议你去看看这个网站 https://peps.python.org/pep-0698/。这个网站很好地解释了如何像在Java中一样给Python的方法添加装饰器。

这里有一个代码示例,想了解更多细节可以查看上面的网站。

from typing import override

class Parent:
    def foo(self) -> int:
        return 1

    def bar(self, x: str) -> str:
        return x

class Child(Parent):
    @override
    def foo(self) -> int:
        return 2

    @override
    def baz() -> int:  # Type check error: no matching signature in ancestor
        return 1
271

根据这个和fwc的回答,我创建了一个可以用pip安装的包,链接是https://github.com/mkorpela/overrides

我时不时会来到这里看看这个问题。主要是因为我又一次在我们的代码中发现了同样的bug:有人在重命名“接口”中的方法时,忘记了某个“接口”实现类。

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

撰写回答