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

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

问题描述

我有两个类应该为两个独立的库实现相同的测试用例(我们称它们为 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屋!

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