python屬性尋找 深入理解(attribute lookup)

來源:互聯網
上載者:User

標籤:python

在Python中,屬性尋找(attribute lookup)是比較複雜的,特別是涉及到描述符descriptor的時候。

   

  在上一文章末尾,給出了一段代碼,就涉及到descriptor與attribute lookup的問題。而get系列函數(__get__, __getattr__, __getattribute__) 也很容易搞暈,本文就這些問題簡單總結一下。

  首先,我們知道:

  •     python中一切都是對象,“everything is object”,包括類,類的執行個體,數字,模組

  •     任何object都是類(class or type)的執行個體(instance)

  •     如果一個descriptor只實現了__get__方法,我們稱之為non-data descriptor, 如果同時實現了__get__ __set__我們稱之為data descriptor。

 

    按照python doc,如果obj是某個類的執行個體,那麼obj.name首先調用__getattribute__。如果類定義了__getattr__方法,那麼在__getattribute__拋出 AttributeError 的時候就會調用到__getattr__,而對於描述符(__get__)的調用,則是發生在__getattribute__內部的。官網文檔是這麼描述的

    The implementation works through a precedence chain that gives data descriptors priority over instance variables, instance variables priority over non-data descriptors, and assigns lowest priority to __getattr__() if provided.

    obj = Clz(), 那麼obj.attr 順序如下:

    (1)如果“attr”是出現在Clz或其基類的__dict__中, 且attr是data descriptor, 那麼調用其__get__方法, 否則

    (2)如果“attr”出現在obj的__dict__中, 那麼直接返回 obj.__dict__[‘attr‘], 否則

    (3)如果“attr”出現在Clz或其基類的__dict__中

        (3.1)如果attr是non-data descriptor,那麼調用其__get__方法, 否則

        (3.2)返回 __dict__[‘attr‘]

    (4)如果Clz有__getattr__方法,調用__getattr__方法,否則

    (5)拋出AttributeError 

  下面是測試代碼:

  

650) this.width=650;" id="code_img_closed_d0bbfca4-224e-4463-8168-7a098b38f1e2" class="code_img_closed" src="/img/jia.gif" style="margin:0px;padding:0px 5px 0px 0px;border:0px;vertical-align:middle;" /> View Code

 

  注意第50行,change_attr給執行個體的__dict__裡面增加了兩個屬性。通過上下兩條print的輸出如下:

  Derive object dict {‘same_name_attr‘: ‘attr in object‘, ‘not_des_attr‘: ‘I am not descriptor attr‘}

  Derive object dict {‘same_name_attr‘: ‘attr in object‘, ‘ndd_derive‘: ‘ndd_derive now in object dict ‘, ‘not_des_attr‘: ‘I am not descriptor attr‘, ‘dd_base‘: ‘dd_base now in object dict ‘}

 

  調用change_attr方法之後,dd_base既出現在類的__dict__(作為data descriptor), 也出現在執行個體的__dict__, 因為attribute lookup的循序,所以優先返回的還是Clz.__dict__[‘dd_base‘]。而ndd_base雖然出現在類的__dict__, 但是因為是nondata descriptor,所以優先返回obj.__dict__[‘dd_base‘]。其他:line48,line56表明了__getattr__的作用。line49表明obj.__dict__優先於Clz.__dict__

 

  前面提到過,類的也是對象,類是元類(metaclass)的執行個體,所以類屬性的尋找順序基本同上,區別在於第二步,由於Clz可能有基類,所以是在Clz及其基類的__dict__尋找“attr"

  

  文末,我們再來看一下這段代碼。

   

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

 1 import functools, time 2 class cached_property(object): 3     """ A property that is only computed once per instance and then replaces 4         itself with an ordinary attribute. Deleting the attribute resets the 5         property. """ 6  7     def __init__(self, func): 8         functools.update_wrapper(self, func) 9         self.func = func10 11     def __get__(self, obj, cls):12         if obj is None: return self13         value = obj.__dict__[self.func.__name__] = self.func(obj)14         return value15 16 class TestClz(object):17     @cached_property18     def complex_calc(self):19         print ‘very complex_calc‘20         return sum(range(100))21 22 if __name__==‘__main__‘:23     t = TestClz()24     print ‘>>> first call‘25     print t.complex_calc26     print ‘>>> second call‘27     print t.complex_calc

650) this.width=650;" src="/img/fz.gif" alt="複製代碼" style="margin:0px;padding:0px;border:none;" />

 

    cached_property是一個non-data descriptor。在TestClz中,用cached_property裝飾方法complex_calc,傳回值是一個descriptor執行個體,所以在調用的時候沒有使用小括弧。

    第一次調用t.complex_calc之前,obj(t)的__dict__中沒有”complex_calc“, 根據尋找順序第三條,執行cached_property.__get__, 這個函數代用緩衝的complex_calcFunction Compute出結果,並且把結果放入obj.__dict__。那麼第二次訪問t.complex_calc的時候,根據尋找順序,第二條有限於第三條,所以就直接返回obj.__dict__[‘complex_calc‘]。bottle的源碼中還有兩個descriptor,非常厲害!


python屬性尋找 深入理解(attribute lookup)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.