5

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

这个概念不正确吗?

4

1 回答 1

6

这个概念是正确的;该ABCMeta代码不区分 aabstractproperty和 a 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'])

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

这些检查在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)

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

于 2013-01-21T15:17:40.293 回答