2014-09-12 62 views
6

在給定的情況下,選擇在給定班級中實施哪些規則,有哪些一般的經驗法則?什麼是決定__get__,__getattr__和__getattribute__之間的一些經驗法則?

我已閱讀文檔,並瞭解它們之間的區別。相反,我正在尋找關於如何通過更好地注意到更細微的機會來使用它們以及何時使用它們來最佳地將其用法集成到我的工作流程中的指導。那種事。有問題的方法是(據我所知):

## fallback 
__getattr__ 
__setattr__ 
__delattr__ 

## full control 
__getattribute__ 
##(no __setattribute__ ? What's the deal there?) 

## (the descriptor protocol) 
__get__ 
__set__ 
__delete__ 
+1

給封閉選民:IMX,學習者的問題如「我如何決定X和Y?」或者「X和Y有什麼區別?」真的有兩個問題 - 「X的預期目的是什麼?」和「Y的預期目的是什麼?」也許最好單獨問問他們,但在目前的情況下,兩者都不是「太寬泛」的海事組織,在這裏不同的魔法方法至少有一些聯繫。 – 2014-09-12 12:55:27

回答

5

__setattribute__不存在,因爲__setattr__總是調用__getattr__僅在f.x(如果通過正常通道(由__getattribute__提供,因此函數總是被調用)失敗)下調用。

描述符協議與其他協議略有正交。鑑於

class Foo(object): 
    def __init__(self): 
     self.x = 5 

f = Foo() 

以下爲真:

  • f.x將調用f.__getattribute__('x'),如果它被定義。
  • f.x如果定義了它將不會調用f.__getattr__('x')
  • f.y將調用f.__getattr__('y')如果它被定義,否則 f.__getattribute__('y')如果被定義它

該描述符由調用的屬性,而不是對的屬性。那就是:

class MyDescriptor(object): 
    def __get__(...): 
     pass 
    def __set__(...): 
     pass 

class Foo(object): 
    x = MyDescriptor() 

f = Foo() 

現在,f.x會導致type(f).__dict__['x'].__get__被調用,並f.x = 3會打電話type(f).__dict__['x'].__set__(3)

也就是說,Foo.__getattr__Foo.__getattribute__將被用於查找f.x引用;一旦你有,f.x產生type(f.x).__get__()如果定義的結果,和f.x = y調用f.x.__set__(y)如果定義。

(以__get____set__以上呼叫只能近似正確的,因爲我已經離開了哪些參數__get____set__實際收到的細節,但是這應該是足以說明__get____getattr[ibute]__之間的區別。)

換言之,如果MyDescriptor沒有定義__get__,那麼f.x只會返回MyDescriptor的實例。

+0

哦..我現在看到了。感謝讓這些連接更清晰。有什麼辦法可以讓'x = 3'(並且符合方法所附的對象) – Inversus 2014-09-12 13:07:18

+0

*(沒有限定... – Inversus 2014-09-14 02:46:47

+0

但是,現在我已經玩了一下了,我認爲__getattribute__是正確的我的用例是當它在一個集合中時,所以我認爲這會起作用,謝謝 – Inversus 2014-09-14 02:48:47

6

對於__getattr__ VS __getattribute__,例如參見Difference between __getattr__ vs __getattribute__

__get__沒有真正相關。我要從這裏引用official documentation for the descriptor protocol

屬性訪問的默認行爲是從對象的字典中獲取,設置或刪除屬性。例如,a.x的查找鏈從a.__dict__['x']開始,然後是type(a).__dict__['x'],並且繼續通過不包含元類的type(a)的基類。如果查找的值是定義其中一個描述符方法的對象,則Python可以覆蓋默認行爲並調用描述符方法。在優先鏈中發生這種情況取決於定義了哪些描述符方法。

__get__的目的是控制什麼發生一次a.x通過該「查找鏈」中找到(例如,創建方法的對象而不是返回經由type(a).__dict__['x']發現純函數); __getattr____getattribute__的目的是改變查找鏈本身。

沒有__setattribute__,因爲只有一種方式,實際上設置了一個對象的屬性,在引擎蓋下。當設置屬性時,您可能想要「神奇地」發生其他事情;但__setattr__涵蓋。 __setattribute__不可能提供__setattr__尚未提供的任何功能。

但是 - 在絕大多數情況下,最好的答案是甚至沒有想到使用任何這些。首先看更高層次的抽象,如property s,classmethod s和staticmethod s。如果你認爲你需要像這樣的專門工具,並且不能爲自己弄明白,那麼你的想法很可能錯了;但無論如何,最好在這種情況下發布更具體的問題。