2016-09-21 134 views
1

我目前正試圖瞭解在使用a+ba.__add__(b)之間的區別是什麼時候涉及到自定義類。有很多網站表示使用'+' - 運算符會導致使用特殊方法__add__ - 目前爲止這很好。a + b和.__之間的區別__(b)

但是,當我運行下面的例子,我得到了兩個不同的結果。

class C: 
    def __add__(self, other): 
    print("C.__add__", self, other) 
    return "result" 
    def __radd__(self, other): 
    print("C.__radd__", self, other)  
    return "reversed result" 

c = C() 
print(1+c) 
print() 
print(1 .__add__(c)) 
print(int.__add__(1,c)) 

結果:

C.__radd__ <C object at 0x7f60b92e9550> 1 
reversed result 

NotImplemented 
NotImplemented 
從我的理解,執行 1+c Python的檢查時/執行INT __add__方法

現在 - 發現有添加int和C對象沒有實現 - 回報NotImplemented - 讓Python知道檢查對象C的__radd__並執行其中的代碼。

爲什麼1+c結果在執行__radd__代碼,但其他兩個版本都只是返回NotImplemented不檢查__radd__

+7

呃,因爲你直接調用了__add__?正如你所說的,當你使用'+'運算符時,Python只會回退。 –

+0

猜測我不知道如果直接使用'__add__',則不會使用回退。 – Korred

回答

3

a+b相當於import operator; operator.add(a,b)。它首先呼叫a.__add__(b),然後,如有必要,b.__radd__(a)。但是ifsubclass(type(b), type(a)),然後b.__radd__(a)被稱爲第一。基於

docs on "special" methods

  • 關於__add__()

    __add__()被調用來實現二進制算術 「+」 操作。例如,要評估表達式x + y,其中x是具有__add__()方法的類的實例,則調用x.__add__(y)

    如果其中一種方法不支持使用提供的參數進行操作,則應返回未實現

  • 關於__radd__()

    如果左操作數不支持相應的操作和操作數是不同類型的這些功能只調用。例如,要評估表達式x + y,其中y是具有方法的類的實例,如果x.__add__(y)返回NotImplemented,則調用y.__radd__(x)

    如果右操作數的類型是左操作數類型的子類,並且該子類提供操作的反射方法,則將在左操作數的非反射方法之前調用此方法。這種行爲允許子類覆蓋其祖先的操作。

基於行爲的例子說明:

案例1:

>>> print 1+c 
('C.__radd__', <__main__.C instance at 0x7ff5631397a0>, 1) 
reversed result 

這些功能radd如果左操作數不支持只叫相應的操作和操作數是不同的類型。在這種情況下,1不支持該類的添加,因此,它回退到C類的__radd__()函數。如果__radd__不是在C()類實現,它會回落到__add__()

案例2:

>>> 1 .__add__(c) 
NotImplemented 
>>> c .__add__(1) 
('C.__add__', <__main__.C instance at 0x7ff563139830>, 1) 
'result' 

1 .__add__(c)NotImplemented1int型和int類的add不支持add與C類對象。但c .__add(1)運行,因爲C()類支持。

案例3:

>>> int.__add__(1, c) 
NotImplemented 
>>> C.__add__(c, 1) 
('C.__add__', <__main__.C instance at 0x7ff5610add40>, 1) 
'result' 

類似case 2。但是在這裏,這個調用是通過第一個參數作爲該類的對象的類來完成的。行爲將是相同的。

案例4:的case 3

>>> int.__add__(c, 1) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: descriptor '__add__' requires a 'int' object but received a 'instance' 
>>> C.__add__(1, c) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
TypeError: unbound method __add__() must be called with C instance as first argument (got int instance instead) 

反之亦然。從堆棧跟蹤中清除,__add__預期調用類的對象作爲第一個參數,失敗則導致異常。

+0

因此,當使用負責回退的'+'運算符時,基本上會發生更多幕後現象? – Korred

+0

更新了答案。我盡力解釋它是如何工作的。如有疑問,請告訴我。我將進一步編輯並嘗試更清晰 –

+0

也許我應該解釋我的問題 - 使用'+'運算符和__add__函數有什麼區別? 閱讀有關特殊方法,它看起來像沒有 - 但顯然'NotImplemented'情況處理不同 – Korred

相關問題