web-dev-qa-db-ja.com

Pythonで「+ =」をオーバーライドしますか? (__iadd __()メソッド)

Pythonで+ =をオーバーライドすることは可能ですか?

59
Evan Fosmark

はい、 __iadd__ メソッド。例:

def __iadd__(self, other):
    self.number += other.number
    return self    
104
John Kugelman

上記の回答で正しく与えられていることに加えて、__iadd__がオーバーライドされると、x += y操作は__iadd__メソッドの終わりで終了しないことを明示的に明確にする価値があります。

代わりに、x = x.__iadd__(y)で終わります。つまり、Pythonは、実装が完了すると、__iadd__実装の戻り値を、「追加」するオブジェクトに割り当てます。

これは、x += y操作の左側を変更して、最終的な暗黙のステップが失敗する可能性があることを意味します。リスト内にあるものに追加するときに何が起こるか考えてください:

>>> x[1] += y # x has two items

これで、__iadd__実装(x[1]のオブジェクトのメソッド)が誤ってまたは意図的にリストの先頭から最初の項目(x[0])を削除した場合、Pythonが__iadd__メソッドを実行します)戻り値をx[1]に割り当ててみてください。存在しなくなり(x[0]になります)、結果はÌndexErrorになります。

または、__iadd__が上記の例のxの先頭に何かを挿入すると、オブジェクトはx[2]ではなくx[1]になり、x[0]で以前にあったものはx[1]になり、__iadd__の戻り値が割り当てられます呼び出し。

何が起きているのか理解していない限り、結果として生じるバグは修正するのが悪夢です。

21
Petri

オーバーロード__iadd__(自己を忘れないでください!)、__add__、x + = yはx = x + yのように機能します。 (これは+ =演算子の落とし穴の1つです。)

>>> class A(object):
...   def __init__(self, x):
...     self.x = x
...   def __add__(self, other):
...     return A(self.x + other.x)
>>> a = A(42)
>>> b = A(3)
>>> print a.x, b.x
42 3
>>> old_id = id(a)
>>> a += b
>>> print a.x
45
>>> print old_id == id(a)
False

それも 専門家を排除する

class Resource(object):
  class_counter = 0
  def __init__(self):
    self.id = self.class_counter
    self.class_counter += 1

x = Resource()
y = Resource()

どのような値を期待しますかx.idy.id、およびResource.class_counter 持つため?

12
Roger Pate

http://docs.python.org/reference/datamodel.html#emulating-numeric-types

たとえば、ステートメントx + = y(xは__iadd __()メソッドを持つクラスのインスタンス)を実行するには、x .__ iadd __(y)が呼び出されます。

5
Unknown