【发布时间】:2021-11-24 07:23:04
【问题描述】:
从 python 3.9 开始,支持堆叠 @property 和 @classmethod 装饰器。但是,我很难创建一个显示在help 中Readonly properties 部分下的类属性。 [1],[2],[3],[4],[5] 中提出的解决方案没有解决我的问题。考虑:
from time import sleep
from abc import ABC, ABCMeta, abstractmethod
def compute(obj, s):
print(f"Computing {s} of {obj} ...", end="")
sleep(3)
print("DONE!")
return "Phew, that was a lot of work!"
class MyMetaClass(ABCMeta):
@property
def expensive_metaclass_property(cls):
"""This may take a while to compute!"""
return compute(cls, "metaclass property")
class MyBaseClass(ABC, metaclass=MyMetaClass):
@classmethod
@property
def expensive_class_property(cls):
"""This may take a while to compute!"""
return compute(cls, "class property")
@property
def expensive_instance_property(self):
"""This may take a while to compute!"""
return compute(self, "instance property")
class MyClass(MyBaseClass):
"""Some subclass of MyBaseClass"""
help(MyClass)
问题是调用help(MyBaseClass) 会多次执行expensive_class_property。这导致过去的文档出现问题,例如 sphinx 最终也会执行属性代码。
使用元类可以避免这个问题,但缺点是expensive_metaclass_property 既不会出现在dir(MyClass) 中,也不会出现在help(MyClass) 中,也不会出现在MyClass 的文档中。如何获得在 help(MyClass) 的 Readonly properties 部分下显示的类属性?
调用help(MyClass)时会发生以下情况:
Computing class property of <class '__main__.MyClass'> ...DONE!
Computing class property of <class '__main__.MyClass'> ...DONE!
Computing class property of <class '__main__.MyClass'> ...DONE!
Computing class property of <class '__main__.MyBaseClass'> ...DONE!
Computing class property of <class '__main__.MyClass'> ...DONE!
Help on class MyClass in module __main__:
class MyClass(MyBaseClass)
| Some subclass of MyBaseClass
|
| Method resolution order:
| MyClass
| MyBaseClass
| abc.ABC
| builtins.object
|
| Data and other attributes defined here:
|
| __abstractmethods__ = frozenset()
|
| ----------------------------------------------------------------------
| Class methods inherited from MyBaseClass:
|
| expensive_class_property = 'Phew, that was a lot of work!'
| ----------------------------------------------------------------------
| Readonly properties inherited from MyBaseClass:
|
| expensive_instance_property
| This may take a while to compute!
|
| ----------------------------------------------------------------------
| Data descriptors inherited from MyBaseClass:
|
| __dict__
| dictionary for instance variables (if defined)
|
| __weakref__
| list of weak references to the object (if defined)
【问题讨论】:
-
是否可以缓存计算结果?还是必须在每次调用时重新计算?
-
@wim 我稍后已经将它与缓存装饰器结合使用。但是,这意味着当它应该执行 0 次时,它仍然至少执行一次,就像
expensive_instance_property一样。 -
好的,所以主要问题实际上并不是多次调用,而是自动文档调用了属性代码?
-
来自 OP 的错误报告:bugs.python.org/issue45356
标签: python-3.x properties metaclass class-method python-3.9