使用@abstractproperty和@abstractmethod实现/覆盖的实际差异

Par*_*ham 5 python properties abc abstract

考虑一个带有函数的抽象基类,您希望每个后续子类都要覆盖它.使用abc模块和ABCMeta; 用装饰器实际装饰@abstractproperty@abstractmethod实际强制子类/开发人员实现创建装饰器指定的函数类型?从我的实验中,您可以使用方法和带有子类中的属性的抽象方法覆盖抽象属性.

这个概念不正确吗?

Mar*_*ers 6

这个概念是正确的; 该ABCMeta代码不一个区分abstractproperty和一个abstractmethod.

这两个装饰器都为装饰项添加了一个属性.__isabstractmethod__,ABCMeta用于将.__abstractmethods__属性(a frozenset)添加到您定义的ABC中.object然后,该类型防止创建任何类的实例,其中列出的任何名称.__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'])
Run Code Online (Sandbox Code Playgroud)

通过在子类中为这些创建新的覆盖,ABCMeta类将找到具有该. __isabstractmethod__属性的更少方法或属性,从而使得结果__abstractmethods__集更小; 一旦set为空,您就可以创建这样一个子类的实例.

这些检查在ABCMeta.__new__构造函数中进行,并且不进行任何检查以匹配描述符类型:

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)
Run Code Online (Sandbox Code Playgroud)

您必须创建一个ABCMeta覆盖该__new__方法的子类,并检查基类上命名的任何抽象方法或属性是否确实与非抽象方法或属性相匹配cls.