Prohibit addition of new methods to a Python child class

给你一囗甜甜゛ 提交于 2021-02-16 18:06:53

问题


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

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.


回答1:


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__ 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")


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.



来源:https://stackoverflow.com/questions/61328355/prohibit-addition-of-new-methods-to-a-python-child-class

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!