アプリ版:「スタンプのみでお礼する」機能のリリースについて

pythonの特殊メソッドの呼ばれ方についての質問です。
例えば、
x + y
を実行した時、
x.__add__(y)
の特殊メソッドが呼ばれると思うのですが、

xの__add__をオーバーロードしてなくて、
yの__radd__をオーバーロードしている場合、
後のオーバーロードした+演算子で解釈される様なのですが、
通常の+の演算子で解釈されるのは、両方の変数(オビジェクト)ともにオーバーロードされていない時という理解でいいのでしょうか?
左辺がオーバーロードされてない時、通常の+演算子、
x.__add__(y)を読み出した時点で、yが通常の変数では無いので、この時点でエラーになる様な気もするので質問しています。

どの様に理解するのがいいのでしょうか?

質問者からの補足コメント

  • どう思う?

    1 + 2
    は、
    1のint型には、__add__メソッドは実装されていない、
    2のint型には、__radd__メソッドは実装されていない
    のに何故、TypeErrorにならないのですか?

    No.1の回答に寄せられた補足コメントです。 補足日時:2020/05/22 21:35
  • どう思う?

    ちょっと教えてください。

    dir(1)
    とすると、同じ様に、
    ['__abs__', '__add__', (略) , '__radd__', (略) ]
    と表示されますが、
    1.__class__

    1.__add__(2)
    はSyntaxErrorになる様ですが、何が悪いのでしょうか?

    また、
    +の後の方のオブジェクトをオーバーロードした時、
    1 + オーバーロードしたオブジェクト
    とすると、
    左辺の1の通常の__add__()が呼び出されてエラーになる様な気がするのですが、
    実際には、オーバーロードオブジェクトの__radd__()が呼ばれて上手くいく様なのですが、
    オーバーロードしたオブジェクトがあれば、そちらが優先されるみたいなルールってあるのですか?

    No.3の回答に寄せられた補足コメントです。 補足日時:2020/05/23 07:49

A 回答 (4件)

この回答への補足あり
    • good
    • 0

当たり前だけど, 組み込みの演算子で対応できるならこいつらの出番はないよ.

    • good
    • 0

> 1 + 2


> は、
> 1のint型には、__add__メソッドは実装されていない、
> 2のint型には、__radd__メソッドは実装されていない

確認しましたか?

>>> a=1
>>> a.__class__
<type 'int'>
>>> dir(a)
['__abs__', '__add__', (略) , '__radd__', (略) ]
>>> a.__add__(2)
3
この回答への補足あり
    • good
    • 0

> 1.__class__


> や
> 1.__add__(2)
> はSyntaxErrorになる様ですが、何が悪いのでしょうか?

浮動小数点数リテラル ( 1.5 とか)の書式の方が優先され、. が小数点と解釈されています。
そのため、続く文字が「浮動小数点数リテラルとしては不正な文字」なためSyntaxError(文法間違い)になります。
(1).__class__
等と括弧でくくるとか、変数と束縛するとかすれば、属性へのアクセスと解釈されます。


> +の後の方のオブジェクトをオーバーロードした時、
> 1 + オーバーロードしたオブジェクト
> とすると、
> 左辺の1の通常の__add__()が呼び出されてエラーになる様な気がするのですが、

https://docs.python.org/ja/3/reference/datamodel …
https://qiita.com/tell-k/items/ec64a82e7883cb00a …

演算子 + は単純な __add__ / __radd__ メソッドへの置き換えではありません。
a + b で __radd__ が呼ばれるのは次のときです。
・a.__add__ メソッドの無い
・a.__add__(b) メソッドが NotImplemented を返した
・b が aのサブクラス、かつ b.__radd__ が定義されている


1 + オーバーロードしたオブジェクト

(1).__add__(オーバーロードしたオブジェクト)
→ NotImplemented

オーバーロードしたオブジェクト.__radd__(1)

という動作をしています。


>>> class cc:
...□def __radd__(self,x):
...□□print("__radd__ -> 5")
...□□return 5
...
>>> c=cc()
>>> c.__class__
<class '__main__.cc'>
>>> dir(c)
[(略), '__radd__',(略)]
>>> 1 + c
__radd__ -> 5
5
>>> (1).__add__(c)
NotImplemented
    • good
    • 0
この回答へのお礼

詳しい説明ありがとうございます。
やっと、理解する事ができました。

お礼日時:2020/05/23 19:18

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!