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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章