【问题标题】:Prohibit addition of new methods to a Python child class禁止向 Python 子类添加新方法
【发布时间】:2020-08-03 07:16:58
【问题描述】:

我有两个类应该为两个独立的库实现相同的测试用例(我们称它们为 LibALibB)。到目前为止,我定义了要在一个抽象基类中实现的测试方法,它确保两个测试类都实现了所有需要的测试:

from abc import ABC, abstractmethod

class MyTests(ABC):
    @abstractmethod
    def test_foo(self):
        pass

class TestsA(MyTests):
    def test_foo(self):
        pass

class TestsB(MyTests):
    def test_foo(self):
        pass

这按预期工作,但仍然可能发生的是,在 LibB 上工作的人不小心将 test_bar() 方法添加到 TestB 而不是基类。在这种情况下,TestA 类中缺少的 test_bar() 将不会被注意到。

有没有办法禁止向(抽象)基类添加新方法?目标是强制在基类中添加新方法,从而强制在所有派生类中实现新方法。

【问题讨论】:

    标签: python python-3.x class inheritance abstract-class


    【解决方案1】:

    是的。它可以通过元类来完成,或者从 Python 3.6 开始,通过检查基类的__init_subclass__

    __init_sublass__ 是语言每次实例化子类时调用的特殊方法。因此它可以检查新类是否具有任何超类中不存在的方法,并在声明子类时引发 TypeError。 (__init_subclass__ 会自动转换为类方法)

    class Base(ABC):
        ...
        def __init_subclass__(cls, *args, **kw):
            super().__init_subclass__(*args, **kw)
            # By inspecting `cls.__dict__` we pick all methods declared directly on the class
            for name, attr in cls.__dict__.items():
                attr = getattr(cls, name)
                if not callable(attr):
                    continue
                for superclass in cls.__mro__[1:]:
                    if name in dir(superclass):
                        break
                else:
                    # method not found in superclasses:
                    raise TypeError(f"Method {name} defined in {cls.__name__}  does not exist in superclasses")
    
    
    

    请注意,与未实现的抽象方法引发的 TypeError 不同,此错误是在类声明时引发的,而不是在类实例化时引发的。如果需要后者,则必须使用元类并将检查移至其__call__ 方法-但这会使事情复杂化,就好像在中间类中创建了一个从未实例化的方法一样,它不会引发该方法在叶子子类中可用。我猜你需要更多的是上面的代码。

    【讨论】:

    • hasattr(cls, name) 可以代替for 循环工作吗?
    • 那里有两个 for 循环。如果你总是有一个基类和直接子类,那么,是的 - `hasattr(name, cls.__mro__[1])` 将代替第二个 for 循环工作。外部 for 循环,显然必须在那里检查所有属性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-12
    • 1970-01-01
    • 2017-04-28
    相关资源
    最近更新 更多