Actual difference in implementing/overriding using @abstractproperty and @abstractmethod

淺唱寂寞╮ 提交于 2019-12-07 06:04:37

问题


Consider an abstract base class with a function which you want each subsequent subclass to override. Using the abc module and ABCMeta; does decorating with @abstractproperty or @abstractmethod actually force the subclass/developer implementing to create the type of function specified by the decorator? From my experiments you can override an abstract property with a method and an abstract method with a property in the subclass.

Is this notion incorrect?


回答1:


The notion is correct; the ABCMeta code does not distinguish between a abstractproperty and a abstractmethod.

Both of these decorators add an attribute to the decorated item, .__isabstractmethod__, which ABCMeta uses to add an .__abstractmethods__ attribute (a frozenset) to the ABC you defined. The object type then guards against creating an instance of any class where any of the names listed in .__abstractmethods__ does not have a concrete implementation. No checks are made for functions versus properties there.

To illustrate:

>>> 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'])

By creating new overrides for these in a subclass, the ABCMeta class will find fewer methods or properties with the . __isabstractmethod__ attribute, thus making the resulting __abstractmethods__ set smaller; once the set is empty you can create instances of such a subclass.

These checks are made in the ABCMeta.__new__ constructor and no checks are made to match descriptor types:

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)

You'd have to create a subclass of ABCMeta that overrides the __new__ method, and check that any abstract method or property named on a base class is indeed matched with a non-abstract method or property on cls instead.



来源:https://stackoverflow.com/questions/14441619/actual-difference-in-implementing-overriding-using-abstractproperty-and-abstra

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!