一、django中通過LazySetting對象來獲取項目的配置,LazySetting對象有什麼特性?為什麼使用這個對象? LazySetting顧名思義,就是延遲獲取配置內容。比如,我們定義了一個對象A,並對其添加了一些屬性,對A初始化時,我們將A的屬性的值設置為空,當我們要訪問A其中的一個屬性 ...
一、django中通過LazySetting對象來獲取項目的配置,LazySetting對象有什麼特性?為什麼使用這個對象?
LazySetting顧名思義,就是延遲獲取配置內容。比如,我們定義了一個對象A,並對其添加了一些屬性,對A初始化時,我們將A的屬性的值設置為空,當我們要訪問A其中的一個屬性時,此時屬性的值為空,我們才載入屬性的值,並將空值設置為對應的值,返回屬性值,下次獲取屬性值時,屬性值不為空,直接返回屬性值。
為什麼要使用LazySetting?
django項目在初始化的時候, 通過LazySetting,我們就可以在django獲取某個配置的值之前,將配置的值先自定義為某個值,django再去獲取該配置的值的時候,配置已經有了值,直接返回該配置的值。
二、django是如何實現LazySetting對象的?
1. 在說LazySetting對象之前,我們先看一下python的類屬性的查找方式:
在查找一個實例化的類屬性的時候
- 首先查找這個類的實例屬性是否存在,存在直接返回
- 如果類的實例屬性中不存在,則在類的類屬性中查找,類屬性中存在,則返回
- 如果類屬性中也不存在,若定義了__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__的方式來獲取預設的值。
三、總結
延遲載入的方式,可以在編程中優化我們類的初始化動作,比如,我們創建了一個類有很多屬性,這些屬性的值都需要通過計算的方式獲取,我們在初始化的時候,就要把屬性的值計算出來,這些計算出來屬性,我們後面有可能能會用不到,這樣的話,類的初始化就計算屬性的值方式會浪費大量的電腦資源;使用延遲載入的方式,就可以很好的解決這種問題,到使用屬性值的時候再獲取。