📜  Python Functools – cached_property()

📅  最后修改于: 2022-05-13 01:55:29.949000             🧑  作者: Mango

Python Functools – cached_property()

@cached_property是一个装饰器,它将类的方法转换为属性,其值仅计算一次,然后作为普通属性缓存。因此,只要实例持续存在,缓存的结果就可用,我们可以将该方法用作类的属性,即

Writing    : instance.method
Instead of : instance.method()

cached_property 是Python中 functools 模块的一部分。它类似于property() ,但 cached_property() 带有一个额外的功能,那就是缓存。

注意:更多信息请参考Python中的 Functools 模块

为什么要缓存?

高速缓存内存是 CPU 内部可用的高速内存,用于加快对数据和指令的访问。因此,缓存是一个可以快速访问的地方。结果可以计算和存储一次,从下一次开始,可以访问结果而无需再次重新计算。因此,它在计算昂贵的情况下很有用。

@property 和 @cached_property 的区别:

# Using @property
  
# A sample class
class Sample():
  
    def __init__(self):
      self.result = 50
  
    @property
    # a method to increase the value of
    # result by 50
    def increase(self):
        self.result = self.result + 50
        return self.result
  
# obj is an instance of the class sample
obj = Sample()
print(obj.increase)
print(obj.increase)
print(obj.increase)

输出

100
150
200

相同的代码,但现在我们使用 @cached_property 而不是 @property

# Using @cached_property
  
from functools import cached_property
  
# A sample class
class Sample():
  
    def __init__(self):
      self.result = 50
  
    @cached_property
    # a method to increase the value of
    # result by 50
    def increase(self):
        self.result = self.result + 50
        return self.result
  
# obj is an instance of the class sample
obj = Sample()
print(obj.increase)
print(obj.increase)
print(obj.increase)

输出

100
100
100

您可以清楚地看到,使用 @property 每次调用 increase() 方法时都会计算结果的值,这就是为什么它的值会增加 50。但是使用@cached_property时,结果的值只计算一次,然后存储在缓存中,以便每次调用 increase() 方法时都可以访问它,而无需重新计算结果的值,这就是为什么每次输出都显示 100 的原因。

但是它如何减少执行时间并使程序更快呢?
考虑以下示例:

# Without using @cached_property
  
# A sample class
class Sample():
  
    def __init__(self, lst):
      self.long_list = lst
  
    # a method to find the sum of the 
    # given long list of integer values
    def find_sum(self):
        return (sum(self.long_list))
  
# obj is an instance of the class sample
# the list can be longer, this is just
# an example
obj = Sample([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(obj.find_sum())
print(obj.find_sum())
print(obj.find_sum())

输出

55
55
55

在这里,假设如果我们传递一个很长的值列表,每次调用find_sum()方法时都会计算给定列表的总和,从而花费大量时间来执行,最终我们的程序会变慢。我们想要的是,因为列表在创建实例后不会改变,所以如果列表的总和只计算一次而不是每次我们调用方法并希望访问和。这可以通过使用@cached_property 来实现

例子:

# With using @cached_property
  
from functools import cached_property
  
# A sample class
class Sample():
    def __init__(self, lst):
      self.long_list = lst
  
    # a method to find the sum of the
    # given long list of integer values
    @cached_property
    def find_sum(self):
        return (sum(self.long_list))
  
# obj is an instance of the class sample
obj = Sample([1, 2, 3, 4, 5, 6, 7, 8, 9, 10])
print(obj.find_sum)
print(obj.find_sum)
print(obj.find_sum)

输出

55
55
55

尽管输出相同,但它大大减少了执行时间。在创建实例时传递的列表的总和只计算一次并存储在缓存中,此后,每次调用 find_sum() 方法时,它使用相同的、已经计算的总和值,节省了我们对总和进行昂贵的重新计算。因此它减少了执行时间并使我们的程序更快。