django LazyObject类研究

django中utils包里面的functional模块里,Lazybject是推迟实例化的类。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class LazyObject(object):
    """
    A wrapper for another class that can be used to delay instantiation of the
    wrapped class.
 
    By subclassing, you have the opportunity to intercept and alter the
    instantiation. If you don't need to do that, use SimpleLazyObject.
    """
 
    # Avoid infinite recursion when tracing __init__ (#19456).
    _wrapped = None
 
    def __init__(self):
        self._wrapped = empty
 
    __getattr__ = new_method_proxy(getattr)
 
    def __setattr__(self, name, value):
        if name == "_wrapped":
            # Assign to __dict__ to avoid infinite __setattr__ loops.
            self.__dict__["_wrapped"= value
        else:
            if self._wrapped is empty:
                self._setup()
            setattr(self._wrapped, name, value)
 
    def __delattr__(self, name):
        if name == "_wrapped":
            raise TypeError("can't delete _wrapped.")
        if self._wrapped is empty:
            self._setup()
        delattr(self._wrapped, name)
         
    def _setup(self):
        """
        Must be implemented by subclasses to initialize the wrapped object.
        """
        raise NotImplementedError('subclasses of LazyObject must provide a _setup() method')


从介绍来说, 可以看出LazyObject的作用就是推迟包装类的实例化,即是需要用的时候,才实例化它。

对于理解这段代码,可以从实际适用来入手。我们只需指定一个要使用的类,传给LazyObject,那么我们

使用LazyObject,就如同使用包装类一样。这种设计,应该是对用户透明的。

当我们使用类时,分为获取属性,添加属性,删除属性。

对应的三种方法,__getatrr__, __setatrr__, __delatrr__。

在python中对三种方法的重载,就可以实现上述的效果。即LazyObject与包装类是透明的。

在LazyObject的三种方法的实现中, 可以看出推迟实例化的实现。

即先判断包装类是否已经实例化,否则实例它(通过实现_setup()方法实现)。


注意到__getattr__方法,是通过 new_method_proxy函数实现的。

new_method_proxy其实是工厂函数。目的也是推迟实例化。

1
2
3
4
5
6
def new_method_proxy(func):
    def inner(self*args):
        if self._wrapped is empty:
            self._setup()
        return func(self._wrapped, *args)
    return inner
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章