未强制执行名称“”上的抽象属性

2024-04-26 21:36:53 发布

您现在位置:Python中文网/ 问答频道 /正文

请考虑以下示例代码:

from abc import ABC, abstractmethod, abstractproperty

class Base(ABC):

    @abstractmethod
    def foo(self) -> str:
        print("abstract")

    @property
    @abstractmethod
    def __name__(self) -> str:
        return "abstract"

    @abstractmethod
    def __str__(self) -> str:
        return "abstract"

    @property
    @abstractmethod
    def __add__(self, other) -> str:
        return "abstract"


class Sub(Base):

    def foo(self):
        print("concrete")

    def __str__(self):
        return "concrete"

    def __add__(self, other) -> str:
        return "concrete"


sub = Sub()
sub.foo()
sub.__name__
print(str(sub))

请注意,子类不实现抽象属性__name__,实际上,当引用__name__时,它从其父类打印为“abstract”:

^{pr2}$

但是,这并不是因为__name__是一个dunder方法,也不是因为@property和{}装饰器不能很好地协同工作,因为如果我从Sub中删除{}的实现,它就不允许我实例化它。(我知道__add__通常不是一个属性,但是我想使用一个'real'dunder方法)如果我删除__str__和{}的实现,就会发生相同的预期行为。只有__name__是这样的。在

是什么导致了这种行为?有没有办法解决这个问题,或者我需要让父(抽象)实现为我手动引发TypeError


Tags: nameselfabstractaddreturnfoodefproperty
1条回答
网友
1楼 · 发布于 2024-04-26 21:36:53

类通过type上的数据描述符有一个__name__属性:

>>> Sub.__name__
'Sub'
>>> '__name__' in Sub.__dict__
False

它是一个数据描述符,因为它还拦截赋值以确保值是字符串。实际值存储在C结构上的槽中,描述符是该值的代理(因此在类上设置新值也不会向__dict__添加新项):

^{2}$

(实际上不触发描述符__get__就访问它是不可能的,因为type本身没有__dict__,而自己有一个__name__)。在

这导致在创建Sub实例时对属性的测试成功,类的毕竟具有该属性:

>>> hasattr(Sub, '__name__')
True

Sub的实例上,Base.__name__实现会被找到,因为实例描述符规则只考虑类和基类,而不考虑元类型。在

相关问题 更多 >