【问题标题】:Lazy class attribute initialization惰性类属性初始化
【发布时间】:2021-11-21 12:36:51
【问题描述】:

我有一个只接受一个输入参数的类。然后,该值将用于计算许多属性(以下示例中只有一个)。如果我只想在调用属性时才进行计算,那么什么是 Pythonic 方式。另外,结果应该被缓存,attr2不能从类外设置。

class LazyInit:
    def __init__(self, val):
        self.attr1 = val
        self.attr2 = self.compute_attr2()

    def compute_attr2(self):
        return self.attr1 * 2  # potentially costly computation


if __name__ == "__main__":
    obj = LazyInit(10)

    # actual computation should take place when calling the attribute
    print(obj.attr2)

【问题讨论】:

标签: python lazy-initialization


【解决方案1】:

attr2 设为属性,而不是实例属性。

class LazyInit:
    def __init__(self, val):
        self.attr1 = val
        self._attr2 = None

    @property
    def attr2(self):
        if self._attr2 is None:
            self._attr2 = self.compute_attr2()
        return self._attr2

_attr2 是一个私有实例属性,它既指示该值是否已经计算,又保存计算的值以供将来访问。

【讨论】:

  • 在某些情况下,使用 cached_property 装饰器可能是一个不错的选择。
【解决方案2】:

正如above 所暗示的那样,只需使用@cached_property 装饰器即可。

from functools import cached_property

class LazyInit():
    ...
    @cached_property
    def attr2(self):
        return <perform expensive computation>

Olvin Roght 正确 points out 表明此解决方案不会像 @property 那样使 attr2 只读。如果这对您很重要,另一种可能是这样写:

    ...
    @property
    def attr2(self):
        return self.__internal_attr2()

    @functools.cached
    def __internal_attr2(self):
        return <perform expensive calculation>

无论如何,Python 提供了一些库来帮助您确保一个值只计算一次。使用它们比尝试自己编写更好。

【讨论】:

  • 正如我在commentaccepted answer 下所说的,它可能是一个选项。引用自文档:cached_property() 的机制与 property() 有所不同”。如果您需要一个属性是只读的或定义自定义设置器cached_property 不是您的选择。
  • 这绝对值得一看!谢谢!
  • @OlvinR​​oght。你是绝对正确的。我编辑了上面的解决方案来处理用户想要只读的情况。
猜你喜欢
  • 2015-11-29
  • 2012-11-25
  • 1970-01-01
  • 2018-05-15
  • 1970-01-01
  • 1970-01-01
  • 2017-09-29
  • 2015-08-06
  • 1970-01-01
相关资源
最近更新 更多