如果我使用抽象方法定义抽象类:
import abc
class A(abc.ABC):
@classmethod
@abc.abstractmethod
def foo(cls):
pass
我无法实例化它(如预期):
>>> A()
TypeError: Can't instantiate abstract class A with abstract methods foo
但是我可以正确地调用它的抽象方法。
>> A.foo()
此行为记录在某处吗?
在Python 3.6和3.7上进行了测试。
答案 0 :(得分:2)
答案 1 :(得分:2)
没有什么是明确的。
abstractmethod
装饰器的文档说:
具有从ABCMeta派生的元类的类,除非其所有抽象方法和属性都被覆盖,否则无法实例化。
PEP 3119说:
包含至少一个用此装饰器声明的尚未被重写的方法的类无法实例化。
及以后
实现:
@abstractmethod
装饰器将函数属性__isabstractmethod__
设置为True。ABCMeta.__new__
方法将类型属性__abstractmethods__
计算为所有具有__isabstractmethod__
属性且其值为true的方法名称的集合。它通过组合基类的__abstractmethods__
属性,在新类dict中添加具有真实__isabstractmethod__
属性的所有方法的名称,以及删除新类中所有方法的名称来实现此目的没有真正的__isabstractmethod__
属性的字典。如果生成的__abstractmethods__
集为非空,则该类被视为抽象类,尝试实例化该类将引发TypeError
。
我对实现部分的解释是@abstractmethod
从不阻止调用该方法,而只是说无法实例化该类,并且除非覆盖了所有抽象方法,否则子类仍将是抽象的。 / p>
所以我不会说这是设计,但至少是一种假定的副作用。
答案 2 :(得分:1)
子类abc.ABC
的子类表示类A
不能直接实例化。
在类型/名称解析期间,@abc.abstractmethod
装饰器会强制检查A
的任何子类。如果class subofA(A):
没有实现修饰的方法,则会引发异常。
一旦通过类型/名称解析,则abstractmethod装饰器不会阻止您调用该方法。毕竟,除非没有实例,否则无法调用该方法。
通过用开发者foo
和@classmethod
装饰@abstractmethod
,您可以指定A.foo()
可以安全地调用而无需实例化类,但是子类{ {1}}必须实现一种重写方法来保留该行为。