禁止向 Python 个子 class 添加新方法
Prohibit addition of new methods to a Python child class
我有两个 class 应该为两个独立的库实现相同的测试用例(我们称它们为 LibA 和 LibB).到目前为止,我定义了要在抽象基础 class 中实现的测试方法,这确保两个测试 classes 都实现了所有需要的测试:
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
而不是基础class。 TestA
class 中缺失的 test_bar()
在这种情况下将不会被注意到。
有没有办法禁止向(抽象)基添加新方法class? objective 是强制在基础 class 中添加新方法,从而强制在所有派生的 classes 中实现新方法。
是的。它可以通过 metaclass 完成,或者从 Python 3.6 开始,检查 baseclass.
的 __init_subclass__
__init_sublass__
是每次实例化 subclass 时由语言调用的特殊方法。因此它可以检查新的 class 是否有任何 superclasses 中不存在的方法,并在声明 subclass 时引发 TypeError。 (__init_subclass__
自动转换为 class 方法)
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")
请注意,与未实现的抽象方法引发的类型错误不同,此错误是在 class 声明时引发的,而不是 class 实例化时引发的。如果需要后者,则必须使用 metaclass 并将检查移至其 __call__
方法 - 然而这会使事情复杂化,就好像在中间 class 中创建一个方法一样,从未实例化,当该方法在叶 subclass 中可用时,它不会引发。我猜你需要的是上面的代码。
我有两个 class 应该为两个独立的库实现相同的测试用例(我们称它们为 LibA 和 LibB).到目前为止,我定义了要在抽象基础 class 中实现的测试方法,这确保两个测试 classes 都实现了所有需要的测试:
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
而不是基础class。 TestA
class 中缺失的 test_bar()
在这种情况下将不会被注意到。
有没有办法禁止向(抽象)基添加新方法class? objective 是强制在基础 class 中添加新方法,从而强制在所有派生的 classes 中实现新方法。
是的。它可以通过 metaclass 完成,或者从 Python 3.6 开始,检查 baseclass.
的__init_subclass__
__init_sublass__
是每次实例化 subclass 时由语言调用的特殊方法。因此它可以检查新的 class 是否有任何 superclasses 中不存在的方法,并在声明 subclass 时引发 TypeError。 (__init_subclass__
自动转换为 class 方法)
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")
请注意,与未实现的抽象方法引发的类型错误不同,此错误是在 class 声明时引发的,而不是 class 实例化时引发的。如果需要后者,则必须使用 metaclass 并将检查移至其 __call__
方法 - 然而这会使事情复杂化,就好像在中间 class 中创建一个方法一样,从未实例化,当该方法在叶 subclass 中可用时,它不会引发。我猜你需要的是上面的代码。