使用@abstractproperty 和@abstractmethod 实现/覆盖的实际差异 [英] Actual difference in implementing/overriding using @abstractproperty and @abstractmethod

查看:23
本文介绍了使用@abstractproperty 和@abstractmethod 实现/覆盖的实际差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

这个概念不正确吗?

解决方案

这个概念是正确的;ABCMeta 代码不区分 abstractpropertyabstractmethod.

这两个装饰器都为被装饰的项目添加了一个属性,.__isabstractmethod__ABCMeta 使用它来添加一个 .__abstractmethods__ 属性(一个frozenset) 到您定义的 ABC.object 类型然后防止创建任何类的实例,其中 .__abstractmethods__ 中列出的任何名称都没有具体实现.那里没有对函数和属性进行检查.

举例说明:

<预><代码>>>>从 abc 导入 *>>>C类:... __metaclass__ = ABCMeta... @抽象方法... def abstract_method(self): 通过... @abstractproperty... def abstract_property(self): 返回 'foo'...>>>C.__抽象方法__冻结集(['abstract_method','abstract_property'])

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

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

cls = super(ABCMeta, mcls).__new__(mcls, name, bases, namespace)# 计算抽象方法名称的集合摘要 = 集合(名称名称,namespace.items() 中的值如果 getattr(value, "__isabstractmethod__", False))对于基中基:对于 getattr(base, "__abstractmethods__", set()) 中的名称:value = getattr(cls, name, None)如果 getattr(value, "__isabstractmethod__", False):摘要.添加(名称)cls.__abstractmethods__ =frozenset(abstracts)

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

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?

解决方案

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.

这篇关于使用@abstractproperty 和@abstractmethod 实现/覆盖的实际差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆