1. 程式人生 > >django源碼分析 LazySetting對象

django源碼分析 LazySetting對象

__weak 屬性 不存在 str int val django fun 初始

一、django中通過LazySetting對象來獲取項目的配置,LazySetting對象有什麽特性?為什麽使用這個對象?

LazySetting顧名思義,就是延遲獲取配置內容。比如,我們定義了一個對象A,並對其添加了一些屬性,對A初始化時,我們將A的屬性的值設置為空,當我們要訪問A其中的一個屬性時,此時屬性的值為空,我們才加載屬性的值,並將空值設置為對應的值,返回屬性值,下次獲取屬性值時,屬性值不為空,直接返回屬性值。

為什麽要使用LazySetting?

django項目在初始化的時候, 通過LazySetting,我們就可以在django獲取某個配置的值之前,將配置的值先自定義為某個值,django再去獲取該配置的值的時候,配置已經有了值,直接返回該配置的值。

二、django是如何實現LazySetting對象的?

1. 在說LazySetting對象之前,我們先看一下python的類屬性的查找方式:

在查找一個實例化的類屬性的時候

  1. 首先查找這個類的實例屬性是否存在,存在直接返回
  2. 如果類的實例屬性中不存在,則在類的類屬性中查找,類屬性中存在,則返回
  3. 如果類屬性中也不存在,若定義了__getattr__方法,則根據__getattr__方法獲取屬性

在python中類屬性和實例屬性會記錄在類的一個內置變量__dict__中,類屬性和實例屬性有各自維護的__dict__

class A:
    a = 類屬性

    def
__init__(self): self.a = 實例屬性 print(A.__dict__) print(A().__dict__)

輸出的結果為

{__module__: __main__, a: 類屬性, __init__: <function A.__init__ at 0x04BBAB28>, __dict__: <attribute __dict__ of A objects>, __weakref__: <attribute __weakref__ of A objects>, 
__doc__: None} {a: 實例屬性}

註意的是,類屬性裏面不只有a屬性,還有一些其他類有關的屬性

我們可以看到,類屬性裏面a的值和實例屬性裏面a的值不一樣。類屬性和實例屬性是分別維護的。

2. 下面我們寫幾個實例化的類查找屬性的例子

第一個例子

class A:
    a = Aa
    b = Bb

    def __init__(self):
        self.a = aa

obj = A()
print(obj.a)
print(obj.b)

輸出的結果是(先在實例屬性中查找,找不到,再到類屬性中查找)

aa
Bb

如果我們print(obj.c)則會報錯,因為在類屬性中和實例屬性中都找不到c

第二個例子

class A:
    a = Aa
    b = Bb

    def __init__(self):
        self.a = aa

    def __getattr__(self, item):
        return cc

obj = A()
print(obj.a)
print(obj.b)
print(obj.c)

輸出的結果和上面類似,只是print(obj.c)不報錯了,因為我們定義了__getattr__方法,實例屬性中和類屬性中都找不到時,就會使用這個方法獲取屬性

aa
Bb
cc

3. django的LazySetting類的實現

LazySetting類的實現就是通過定義__getattr__方法實現的,LazySetting類的__getattr__源碼如下

def __getattr__(self, name):
    """Return the value of a setting and cache it in self.__dict__."""
    if self._wrapped is empty:
        self._setup(name)
    val = getattr(self._wrapped, name)
    self.__dict__[name] = val
    return val

我們在LazySetting對象中查找一個屬性的時候,先在實例屬性(self.__dict__)中查找,沒有找到話,通過__getattr__方式獲取,獲取到後,將屬性值保存到實例屬性中,這樣就實現了屬性在使用的時候

再獲取,然後保存。我們還可以再獲取屬性之前,先將屬性的值自定義,這樣就可以不用使用__getattr__的方式來獲取默認的值。

django源碼分析 LazySetting對象