禁止向Python子类添加新方法 [英] Prohibit addition of new methods to a Python child class
问题描述
我有两个类应该为两个独立的库实现相同的测试用例(我们称它们为 LibA 和 LibB ).到目前为止,我定义了要在抽象基类中实现的测试方法,该方法可确保两个测试类均实现所有所需的测试:
I have two classes that are supposed to implement the same test cases for two independent libraries (let's call them LibA and LibB). So far I define the test methods to be implemented in an abstract base class which ensures that both test classes implement all desired tests:
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()
不会引起注意.
This works as expected, but what may still happen is that someone working on LibB accidentally adds a test_bar()
method to TestB
instead of the base class. The missing test_bar()
in the TestA
class would go unnoticed in that case.
是否有一种方法可以禁止向(抽象)基类中添加新方法?目的是强制在基类中添加新方法,从而在所有派生类中强制实施新方法.
Is there a way to prohibit the addition of new methods to an (abstract) base class? The objective is to force the addition of new methods to happen in the base class and thus force the implementation of new methods in all derived classes.
推荐答案
是.可以通过元类或从Python 3.6开始,通过检查基类的 __ init_subclass __
来完成.
Yes. It can be done through a metaclass, or from Python 3.6 onwards, with a check in __init_subclass__
of the baseclass.
__ init_sublass __
是特殊的方法,每次实例化子类时,该语言都会调用该方法.因此,它可以检查新类是否具有在任何超类中都不存在的任何方法,并在声明子类时引发TypeError.( __ init_subclass __
会自动转换为类方法)
__init_sublass__
is a special method called by the language each time a subclass is instantiated. So it can check if the new class have any method that is not present in any of the superclasses and raise a TypeError when the subclass is declared. (__init_subclass__
is converted to a classmethod automatically)
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 __
方法-但是,这会使事情复杂化,就像在中间类中创建了一个从未实例化的方法一样,它当该方法在leaf子类中可用时,不会提高.我想您需要的是上面的代码.
Note that unlike the TypeError raised by non-implemented abstractmethods, this error is raised at class declaration time, not class instantiation time. If the later is desired, you have to use a metaclass and move the check to its __call__
method - however that complicates things, as if one method is created in an intermediate class, that was never instantiated, it won't raise when the method is available in the leaf subclass. I guess what you need is more along the code above.
这篇关于禁止向Python子类添加新方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!