请考虑以下示例代码:
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”:
但是,这并不是因为__name__
是一个dunder方法,也不是因为@property
和{Sub
中删除{__add__
通常不是一个属性,但是我想使用一个'real'dunder方法)如果我删除__str__
和{__name__
是这样的。在
是什么导致了这种行为?有没有办法解决这个问题,或者我需要让父(抽象)实现为我手动引发TypeError
?
类通过
type
上的数据描述符有一个__name__
属性:它是一个数据描述符,因为它还拦截赋值以确保值是字符串。实际值存储在C结构上的槽中,描述符是该值的代理(因此在类上设置新值也不会向
^{2}$__dict__
添加新项):(实际上不触发描述符
__get__
就访问它是不可能的,因为type
本身没有__dict__
,而自己有一个__name__
)。在这导致在创建
Sub
实例时对属性的测试成功,类的毕竟具有该属性:在
Sub
的实例上,Base.__name__
实现会被找到,因为实例描述符规则只考虑类和基类,而不考虑元类型。在相关问题 更多 >
编程相关推荐