首页 > 解决方案 > Python 何时检查 ABC 的具体子类是否实现了所需的方法?

问题描述

在尝试编写单元测试来检查抽象基类的具体子类是否真的在实例化时引发 TypeError 如果未实现所需方法之一,我偶然发现了一些东西,这让我想知道何时检查所需的方法是否已定义由具体的子类实际执行。

到目前为止,我会说:在对象实例化时,因为这是在运行程序时实际引发异常的时间。

但是看看这个片段:

import abc

class MyABC(abc.ABC):
    @abstractmethod
    def foo(self): pass

MyConcreteSubclass(MyABC):
    pass

正如预期的那样,尝试实例化 MyConcreteSubclass 会引发 TypeError:

>>> MyConcreteSubclass()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-39-fbfc0708afa6> in <module>()
----> 1 t = MySubclass()

TypeError: Can't instantiate abstract class MySubclass with abstract methods foo

但是如果我首先声明一个有效的子类然后删除这个方法会发生什么让我感到惊讶:

class MyConcreteSubclass(MyABC):
    def foo(self):
        print("bar")

MyConcreteSubclass.foo
--> <function __main__.MyConcreteSubclass.foo(self)>


>>> t = MyConcreteSubclass()
>>> t.foo()
bar

>>> del MyConcreteSubclass.foo
>>> MyConcreteSubclass.foo
<function __main__.MyABC.foo(self)>

>>> t = MyConcreteSubclass()
>>> print(t.foo())
None

这当然不是我所期望的。在删除后检查 MyConcreteSubclass.foo 时,我们看到通过方法 Resolution order 检索到了基类的 Abstract 方法,这与我们一开始没有在具体子类中实现 foo 的行为相同。

但是在实例化之后 TypeError 不会被引发。所以我想知道,当解释器评估具体子类的主体时,是否已经执行了所需方法的检查?如果是这样,为什么只有在有人尝试实例化子类时才会引发 TypeErrors?

上面显示的测试是使用 Python 3.6.5 执行的。

标签: pythonpython-3.xabstract-classtypeerror

解决方案


它发生在类创建时。在 Python 3.7 中,它在 C 中,在compute_abstract_methodsin 中Modules/_abc.c,被称为ABCMeta.__new__.

顺便说一句,文档确实提到了

不支持向类动态添加抽象方法,或在方法或类创建后尝试修改其抽象状态。


推荐阅读