这是 Django 框架中的一个装饰器类,用于将方法转换为缓存属性
核心功能
cached_property 是一个描述符(descriptor),它将一个方法转换为属性,并且只在第一次访问时执行该方法,之后的访问会直接返回缓存的结果。
import time
# 这个装饰器将单参数方法(只有 self)转换为实例上的缓存属性。
class cached_property:
"""
Decorator that converts a method with a single self argument into a
property cached on the instance.
A cached property can be made out of an existing method:
(e.g. ``url = cached_property(get_absolute_url)``).
"""
name = None
@staticmethod
def func(instance):
raise TypeError(
"Cannot use cached_property instance without calling "
"__set_name__() on it."
)
def __init__(self, func):
self.real_func = func
self.__doc__ = getattr(func, "__doc__")
def __set_name__(self, owner, name):
if self.name is None:
self.name = name
self.func = self.real_func
elif name != self.name:
raise TypeError(
"Cannot assign the same cached_property to two different names "
"(%r and %r)." % (self.name, name)
)
def __get__(self, instance, cls=None):
"""
Call the function and put the return value in instance.__dict__ so that
subsequent attribute access on the instance returns the cached value
instead of calling cached_property.__get__().
"""
if instance is None:
return self
res = instance.__dict__[self.name] = self.func(instance)
return res
class MyClass:
@cached_property
def expensive_operation(self):
print("Computing...")
time.sleep(5)
return 100
obj = MyClass()
print(obj.expensive_operation) # 第一次:打印 "Computing..." 并计算
print(obj.expensive_operation) # 第二次:直接返回缓存结果,不打印 "Computing..."
工作原理
- 第一次访问: 触发
__get__方法,执行原函数,将结果存储在instance.__dict__[name] - 后续访问: Python 的属性查找机制会在
__dict__中找到值,直接返回,不再调用__get__