python 3.9 的一个小插件是
在 3.9 版更改:类方法现在可以包装其他描述符,例如 property()。
这在几种情况下很有用,例如作为在类方法上使用 property()的解决方案,或者为了通过配方创建本质上是一个懒惰评估的类属性
class A:
@classmethod
@property
@cache
def lazy_class_attribute(cls):
"""Method docstring."""
return expensive_computation(cls)
这在python中运行良好,导入类,实例化它或它的子类不会导致expensive_computation
发生,但是似乎两者pydoc
并且sphinx
不仅会expensive_computation
在他们尝试获取文档字符串时导致执行,而且不会为此显示任何文档字符串@classmethod
任何。
问题:是否有可能 - 从 python (*) 中 - 懒惰地评估在构建文档时未执行的类属性/属性?
(*)停止 Sphinx 执行缓存的类方法属性中提出的一种解决方法,感谢 /u/jsbueno,包括根据环境变量修改函数体:
def lazy_class_attribute(cls):
"""Method docstring."""
if os.environ.get("GENERATING_DOCS", False):
return
return expensive_computation(cls)
我非常喜欢这种解决方法,因为特别是,它允许人们在记录时呈现不同的输出。(例如,我的类具有基于类名的路径属性。如果不同的用户执行相同的脚本,则路径将不同,因为它们的主文件夹不同。)
但是有两个问题:
- 这种方法取决于在 python 之外做的事情,imo,在理想的世界中,没有必要在 python 本身之外做
- 为了在文档中获取文档字符串,似乎我们最终不得不做一些不直观的事情,比如
class MetaClass:
@property
@cache
def _expensive_function(cls):
"""some expensive function"""
class BaseClass(metaclass=MetaClass):
lazy_attribute: type = classmethod(MetaClass._expensive_funcion)
"""lazy_attribute docstring"""
PS:顺便问一下, a@classmethod@property
和 an之间有什么功能上的区别attribute
吗?它们看起来非常相似。目前我能做出的唯一区别是,如果该属性需要访问其他@classmethod
s,我们需要像上面一样移动元类中的所有内容。