首页 > 代码库 > django 中的延迟加载技术,python中的lazy技术

django 中的延迟加载技术,python中的lazy技术

---恢复内容开始---

说起lazy_object,首先想到的是django orm中的query_set、fn.Stream这两个类。

query_set只在需要数据库中的数据的时候才 产生db hits。Stream对象只有在用到index时才会去一次次next。

例子:
   f = Stream()
        fib = f << [0, 1] << iters.map(add, f, iters.drop(1, f))

 1行生成了斐波那契数列。

说明:

  f是个lazy的对象,f首先放入了0和1,然后放入了迭代器iters.map。等f[2]的时候。就会调用1次next(iters.map(add, f, iters.drop(1, f))),在map的迭代器中,next(f)和next(drop(1,f))被放到add两端。

很高端大气上档次有木有!

这里有个django的lazy的实现代码,

 对象的

#coding: utf-8
#
class LazyProxy(object):

    def __init__(self, cls, *args, **kwargs):

        self.__dict__[_cls] = cls
        self.__dict__[_params] = args
        self.__dict__[_kwargs] = kwargs

        self.__dict__["_obj"]=None

    def __getattr__(self, item):

        if self.__dict__[_obj] is None:
            self._init_obj()

        return getattr(self.__dict__[_obj], item)


    def __setattr__(self, key, value):

        if self.__dict__[_obj] is None:
            self._init_obj()

        setattr(self.__dict__[_obj], key , value)


    def _init_obj(self):

        self.__dict__[_obj]=object.__new__(self.__dict__[_cls],
                                             *self.__dict__[_params],
                                             **self.__dict__[_kwargs])
        self.__dict__[_obj].__init__(*self.__dict__[_params],
                                       **self.__dict__[_kwargs])


class LazyInit(object):

    def __new__(cls, *args, **kwargs):
        return LazyProxy(cls, *args, **kwargs)


class A(LazyInit):

    def __init__(self, x):

        print ("Init A")
        self.x = 14 + x


a = A(1)
print "Go"
print a.x

原理:在类的__new__方法中hook一下,使其返回lazy_proxy 的对象。然后调用__init__方法时,其实就是调用proxy的__init__方法,第一次调用时

也就是当A生成实例时,Proxy才会真正产生一个A的类,并初始化这个类,注意,在这里proxy的init中得到的cls是A而不是Lazy_Init,因为只有A(1)调用时A的__new__才会调用,虽然__new__名字的查找在LazyInit中。


函数的lazy:

""" 
lazy - Decorators and utilities for lazy evaluation in Python 
Alberto Bertogli (albertito@blitiri.com.ar) 
"""  
  
class _LazyWrapper:  
    """Lazy wrapper class for the decorator defined below. 
    It‘s closely related so don‘t use it. 
 
    We don‘t use a new-style class, otherwise we would have to implement 
    stub methods for __getattribute__, __hash__ and lots of others that 
    are inherited from object by default. This works too and is simple. 
    I‘ll deal with them when they become mandatory. 
    """  
    def __init__(self, f, args, kwargs):  
        self._override = True  
        self._isset = False  
        self._value = None  
        self._func = f  
        self._args = args  
        self._kwargs = kwargs  
        self._override = False  
  
    def _checkset(self):  
        print 111111111111, self._isset, self._value  
        if not self._isset:  
            self._override = True  
            self._value = self._func(*self._args, **self._kwargs)  
            self._isset = True  
            self._checkset = lambda: True  
            self._override = False  
  
    def __getattr__(self, name):  
        print ----------getattr----,  name  
        if self.__dict__[_override]:  
            return self.__dict__[name]  
        self._checkset()  
        print @@@@@@@@@, self._value, type(self._value), name, self._value.__getattribute__(name)  
        return self._value.__getattribute__(name)  
  
    def __setattr__(self, name, val):  
        print ----------setattr----,  name, val  
        if name == _override or self._override:  
            self.__dict__[name] = val  
            return  
        self._checkset()  
        print 222222222222222  
        setattr(self._value, name, val)  
        return  
  
def lazy(f):  
    "Lazy evaluation decorator"  
    def newf(*args, **kwargs):  
        return _LazyWrapper(f, args, kwargs)  
  
    return newf  
 
 
@lazy  
def quick_exe():  
    print ---------quick exe-----------  
    return quickquick  
  
import pdb  
#pdb.set_trace()  
  
quick_exe()  
print #####################  
print quick_exe()

 

 

---恢复内容结束---