class cached_property(object):
"""
Decorator that converts a method with a single self argument into a
property cached on the instance.
Optional ``name`` argument allows you to make cached properties of other
methods. (e.g. url = cached_property(get_absolute_url, name='url') )
"""
def __init__(self, func, name=None):
self.func = func
self.__doc__ = getattr(func, '__doc__')
self.name = name or func.__name__
def __get__(self, instance, cls=None):
if instance is None:
return self
res = instance.__dict__[self.name] = self.func(instance)
return res
装饰器类解释:
1. cache_propery为一个装饰器类,装饰某个函数
2. 定义了一个name参数,可以自己传或者直接读取被装饰的函数名
3. __get__方法表名这个装饰器是个描述符装饰器并且为非数据描述符
4. 这个get方法执行了被装饰的函数并将返回的数据保存到了实例的__dict__里面
5. 属性的读取优先级你应该要了解:数据描述符 > __dict__读取 > 非数据描述符
class RawDb(object):
@cached_property
def columns(self):
return 1
rd = RawDb()
print(rd.__dict__)
print(rd.columns)
print(rd.__dict__)
print(rd.columns)
上面的打印输出:
{}
1
{'columns': 1}
1
解释如下:
1. 实例rd第一次运行rd.columns,会调用__get__方法并将返回的数据保存在实例rd的__dict__里面’
2. 访问rd.columns的时候,为什么会直接去调用描述符的 __get__ 方法?因为当访问的属性为描述符时,会将 rd.columns 转化为RawDb.__dict__[‘columns’].__get__(rd, RawDb) 来访问。
2. 实例rd第二次运行rd.columns,为什么不在运行__get__方法?这是因为__dict__的读取优先于非数据描述符,上面第一次运行我们已经把返回数据保存到了__dict__中,所以直接从__dict__中读取了。