【发布时间】:2021-10-16 04:12:09
【问题描述】:
我一直在尝试查看是否可以通过混合三个装饰器来创建抽象类属性(在 Python 3.9.6 中,如果这很重要的话),我注意到一些奇怪的行为。
考虑以下代码:
from abc import ABC, abstractmethod
class Foo(ABC):
@classmethod
@property
@abstractmethod
def x(cls):
print(cls)
return None
class Bar(Foo):
@classmethod
@property
def x(cls):
print("this is executed")
return super().x
这个输出
this is executed
<class '__main__.Bar'>
这意味着不知何故,Bar.x 最终被调用了。
PyCharm 警告我 Property 'self' cannot be deleted。如果我颠倒@classmethod 和@property 的顺序,则不会调用Bar.x,但我仍然会收到相同的警告,还有另一个警告:This decorator will not receive a callable it may expect; the built-in decorator returns a special object(每当我将@property 放在@987654331 上方时,也会出现这种情况@)。
删除三个装饰器中的任何一个(进行适当的更改:在删除 @property 时添加 () 或在删除 @classmethod 时将 cls 更改为 self)也会阻止调用 Bar.x。
我想所有这一切都意味着直接混合这些装饰器可能只是一个坏主意(正如此处关于其他线程中的类属性的讨论所表明的那样)。
不过,我很好奇:这里发生了什么?为什么要调用 Bar.x?
【问题讨论】:
-
当你说“类属性”时,你想达到什么目的?您可能不应该尝试混合使用
property和classmethod,而是创建您自己的自定义描述符。那会更理智。 -
@juanpa.arrivillaga:现在实际上支持混合
classmethod和property- 他们改变了classmethod与任意描述符的交互方式。 -
@user2357112supportsMonica 啊,是的。我实际上记得在新的和改进的 Descriptor HOWTO 中看到了这一点,基本上它检查函数是否有
__get__并使用类调用它。 -
@user2357112supportsMonica:没有
@abstractmethod也能正常工作的事实让我觉得是这样!您还记得此功能/更改记录在哪里吗?我想看看细节。 -
@tomasz:我不确定是否有任何详细的文档。我只有
classmethoddocs 中的这条注释:“在 3.9 版中更改:类方法现在可以包装其他描述符,例如 property()。”
标签: python abstract-class python-decorators