代码改变世界

利用decorator和descriptor进行数据缓存

2013-07-31 22:50  ubunoon  阅读(939)  评论(0编辑  收藏  举报
class cached_property(object):                                                                                                                           

    def __init__(self, func, name=None, doc=None):
        self.__name__ = name or func.__name__
        self.__module__ = func.__module__
        self.__doc__ = doc or func.__doc__
        self.func = func

    def __get__(self, obj, type=None):
        if obj is None:
            return self
        value = obj.__dict__.get(self.__name__, None)
        if value is None:
            value = self.func(obj)
            obj.__dict__[self.__name__] = value
        return value

 

今天在werkzurg上看到上面的代码,写得真是精彩!

 

通常我们descrator是这么写的

def cached_property(func):
    def _(*args, **kwargs):
            return func(*args, **kwargs)
    return _

 

从代码形式上看,这是一个函数调用,返回一个函数,在python语法上decorator为下面的编写方式:

@cached_property
def func():
      return 42

 

而代码的执行方式和cached_property(func)是一样的,这是一种闭包的形式,这种形式和定义一个object,__init__第一个参数是func,之后定义一个__call__是等价的。在werkzurg中采用了前面的方式__init__来获取和decorator相同的行为,而__init__返回的是cached_property对象,这个对象使用__get__这个descriptor特性。

 

当调用@cached_property修饰的属性名称时,便会调用生成的对象的__get__方法,从而可以更加仔细的调用func方法获取具体的值,从而缓存起来!!!

 

对descriptor不熟悉的可以看python文档:http://docs.python.org/2/howto/descriptor.html

 

perfect!