222

+=の標準表記とは異なる効果があると言われましたi = i +i += 1と違う場合はありi = i + 1ますか?

4

3 に答える 3

339

これは完全にオブジェクトに依存しますi

+=__iadd__メソッドを呼び出します(存在する場合-存在__add__しない場合はフォールバックします)が、メソッド1または場合によってはメソッド2+を呼び出します。__add____radd__

APIの観点からは、変更可能なオブジェクトを適切に変更する(変更さたオブジェクトを返す)__iadd__ために使用されることになっていますが、何かの新しいインスタンスを返す必要があります。不変オブジェクトの場合、どちらのメソッドも新しいインスタンスを返しますが、古いインスタンスと同じ名前で新しいインスタンスを現在の名前空間に配置します。これが理由です__add____iadd__

i = 1
i += 1

インクリメントするようiです。実際には、新しい整数を取得して「上に」割り当てiます。古い整数への参照が1つ失われます。この場合、i += 1はとまったく同じi = i + 1です。しかし、ほとんどの可変オブジェクトでは、それは別の話です。

具体的な例として:

a = [1, 2, 3]
b = a
b += [1, 2, 3]
print a  #[1, 2, 3, 1, 2, 3]
print b  #[1, 2, 3, 1, 2, 3]

に比べ:

a = [1, 2, 3]
b = a
b = b + [1, 2, 3]
print a #[1, 2, 3]
print b #[1, 2, 3, 1, 2, 3]

最初の例では、同じオブジェクトbを参照しているので、で使用すると、実際に変更されます(そして、その変更も確認されます-結局のところ、同じリストを参照しています)。ただし、2番目のケースでは、これを行うと、参照しているリストが取得され、新しいリストと連結されます。次に、連結されたリストを現在の名前空間に-として格納します。前の行が何であったかは関係ありません。a+=bbab = b + [1, 2, 3]b[1, 2, 3]bb


1x + yで、x.__add__が実装されていない場合、またはがx.__add__(y)返さNotImplemented れ、 xタイプyが異なる場合は、x + yを呼び出そうとしますy.__radd__(x)。だから、あなたが持っている場合

foo_instance += bar_instance

Fooが実装されていない場合、__add__または__iadd__ここでの結果はと同じです

foo_instance = bar_instance.__radd__(bar_instance, foo_instance)

2foo_instance + bar_instanceで、のタイプが(eg )のタイプのサブクラスである場合bar_instance.__radd__は前に試行されます。これの理論的根拠は、ある意味で「より高いレベルの」オブジェクトであるため、の動作をオーバーライドするオプションを取得する必要があるということです。foo_instance.__add__ bar_instancefoo_instanceissubclass(Bar, Foo)BarFooBarFoo

于 2013-03-13T03:25:31.807 に答える
68

裏で、i += 1このようなことをします:

try:
    i = i.__iadd__(1)
except AttributeError:
    i = i.__add__(1)

このi = i + 1ようなことをしている間:

i = i.__add__(1)

これは少し単純化しすぎていますが、あなたは考えを理解します。Pythonは、メソッドと+=を作成することによって、型に特別に処理する__iadd__方法を提供します__add__

のような不変の型は、listで自分自身を変異させます__iadd__(そして、self非常にトリッキーなことをしている場合を除いて、を返します)が、のような不変の型は、intそれを実装しません。

例えば:

>>> l1 = []
>>> l2 = l1
>>> l1 += [3]
>>> l2
[3]

l2はと同じオブジェクトであり、l1変更したためl1、も変更しましたl2

だが:

>>> l1 = []
>>> l2 = l1
>>> l1 = l1 + [3]
>>> l2
[]

ここでは、変異していませんl1。代わりに、新しいリストを作成しl1 + [3]、名前をリバウンドしてそれをポイントし、元のリストl1をポイントしたままにします。l2

(この+=バージョンでは、再バインドも行っl1ていました。その場合は、既にバインドされているものと同じlistものに再バインドしていたため、通常はその部分を無視できます。)

于 2013-03-13T03:29:52.890 に答える
6

i += xこれは、以下と直接比較する例ですi = i + x

def foo(x):
  x = x + [42]

def bar(x):
  x += [42]

c = [27]
foo(c); # c is not changed
bar(c); # c is changed to [27, 42]
于 2014-08-23T14:57:32.200 に答える