2016-09-21 14 views
1

現在、a+ba.__add__(b)の違いは、カスタムクラスの場合です。 '+'演算子を使用すると特別なメソッド__add__が使用されるというWebサイトが数多くあります。a + bと.__ addの違い__(b)

しかし、次の例を実行すると2つの異なる結果が得られます。

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)) 

結果:

/ 1+c Pythonのチェックを実行INT __add__方法を実行する際に、私は、理解ものから今
C.__radd__ <C object at 0x7f60b92e9550> 1 
reversed result 

NotImplemented 
NotImplemented 

- 戻るNotImplemented - INTを追加し、Cのオブジェクトはのための実装がないことを認めます - PythonはオブジェクトCのチェックを行い、__radd__のコードを実行します。

1+c__radd__コードを実行しますが、他の2つのバージョンは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)が呼び出されます。

    これらのメソッドのいずれかが、指定された引数での操作をサポートしていない場合は、NotImplementedを返します。 __radd__()について

  • :左オペランドは、対応する操作をサポートしていないとオペランドのタイプが異なる場合、これらの関数はのみ呼び出され

    。たとえば、式x + y(yは、__radd__()メソッドを持つクラスのインスタンス)を評価するには、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__()関数に戻ります。 C()クラスで実装されていませケース__radd__には、ケース2バック__add__()

に下落しているだろうした

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

1 .__add__(c)1としてNotImplementedを与えるintタイプのものであり、intクラスのaddはサポートしないadd Cクラスのオブジェクト。しかし、C()クラスがそれをサポートしているので、c .__add(1)が実行されます。

ケース3:case 2から

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

同様。しかし、ここでは、そのクラスのオブジェクトとして第1引数を持つクラスを介して呼び出しが行われます。行動は同じです。

ケース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

関連する問題