- 主要区别在于
lru_cache 将保持缓存中的对象处于活动状态,这可能会导致内存泄漏,尤其是在应用 lru_cache 的实例很大时(请参阅:https://bugs.python.org/issue19859)
class A:
@property
@functools.lru_cache(maxsize=None)
def x(self):
return 123
for _ in range(100):
A().x # Call lru_cache on 100 different `A` instances
# The instances of `A()` are never garbage-collected:
assert A.x.fget.cache_info().currsize == 100
使用cached_property,没有缓存,所以没有内存泄漏。
class B:
@functools.cached_property
def x(self):
return 123
b = B()
print(vars(b)) # {}
b.x
print(vars(b)) # {'x': 123}
del b # b is garbage-collected
- 另一个区别是
@property 是只读的,而@cached_property 不是。 cache_property 允许写入属性 Refer Python docs
A().x = 123
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
B().x = 123 # Works
这是因为 @cached_property 正在替换属性,所以对 b.x 的第二次调用绕过了 B.x.get 描述符调用。
- 另一个在大多数情况下可能无关紧要的区别是,如果您多次访问同一个属性,
cached_property 的性能会更高,而lru_cache 有函数调用和属性查找的开销。请注意,只有大数字才能看到差异。
[A().x for _ in range(10_000)]
[B().x for _ in range(10_000)]
a = A()
b = B()
print(timeit.timeit(lambda: a.x, number=1_000_000)) # ~0.83
print(timeit.timeit(lambda: b.x, number=1_000_000)) # ~0.57