这个想法是正确的;这ABCMeta
代码不区分abstractproperty
and a abstractmethod
.
这两个装饰器都向装饰项添加属性,.__isabstractmethod__
, which ABCMeta
用于添加一个.__abstractmethods__
属性(一个frozenset
) 到您定义的 ABC。这object
然后 type 防止创建任何类的实例,其中列出的任何名称.__abstractmethods__
没有具体的实现。不对那里的函数和属性进行检查。
为了显示:
>>> from abc import *
>>> class C:
... __metaclass__ = ABCMeta
... @abstractmethod
... def abstract_method(self): pass
... @abstractproperty
... def abstract_property(self): return 'foo'
...
>>> C.__abstractmethods__
frozenset(['abstract_method', 'abstract_property'])
通过在子类中为这些创建新的覆盖,ABCMeta
类会发现更少的方法或属性. __isabstractmethod__
属性,从而使得结果__abstractmethods__
设置较小;一旦集合为空,您就可以创建此类子类的实例。
这些检查是在ABCMeta.__new__构造函数 http://hg.python.org/cpython/file/2.7/Lib/abc.py#l86并且不检查是否匹配描述符类型:
cls = super(ABCMeta, mcls).__new__(mcls, name, bases, namespace)
# Compute set of abstract method names
abstracts = set(name
for name, value in namespace.items()
if getattr(value, "__isabstractmethod__", False))
for base in bases:
for name in getattr(base, "__abstractmethods__", set()):
value = getattr(cls, name, None)
if getattr(value, "__isabstractmethod__", False):
abstracts.add(name)
cls.__abstractmethods__ = frozenset(abstracts)
你必须创建一个子类ABCMeta
覆盖__new__
方法,并检查基类上命名的任何抽象方法或属性确实与非抽象方法或属性匹配cls
反而。