django LazyObject類研究

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的做用就是推遲包裝類的實例化,便是須要用的時候,才實例化它。python

對於理解這段代碼,能夠從實際適用來入手。咱們只需指定一個要使用的類,傳給LazyObject,那麼咱們app

使用LazyObject,就如同使用包裝類同樣。這種設計,應該是對用戶透明的。ide

當咱們使用類時,分爲獲取屬性,添加屬性,刪除屬性。函數

對應的三種方法,__getatrr__, __setatrr__, __delatrr__。oop

在python中對三種方法的重載,就能夠實現上述的效果。即LazyObject與包裝類是透明的。spa

在LazyObject的三種方法的實現中, 能夠看出推遲實例化的實現。設計

即先判斷包裝類是否已經實例化,不然實例它(經過實現_setup()方法實現)。code


注意到__getattr__方法,是經過 new_method_proxy函數實現的。orm

new_method_proxy實際上是工廠函數。目的也是推遲實例化。ci

def new_method_proxy(func):
    def inner(self, *args):
        if self._wrapped is empty:
            self._setup()
        return func(self._wrapped, *args)
    return inner
相關文章
相關標籤/搜索