禁止向 Python 子类添加新方法 [英] Prohibit addition of new methods to a Python child class

查看:18
本文介绍了禁止向 Python 子类添加新方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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__ 方法 - 然而,这使事情复杂化,好像在中间类中创建了一个方法,该方法从未被实例化,它当方法在叶子类中可用时不会引发.我想你需要更多的是上面的代码.

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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆