1. ホーム
  2. パイソン

[解決済み】Pythonで「i += x」と「i = i + x」が異なるのはどんなとき?

2022-04-08 03:31:15

質問

と言われましたが += の標準的な表記とは異なる効果をもたらすことがあります。 i = i + . というケースはあるのでしょうか? i += 1 とは異なります。 i = i + 1 ?

解決方法は?

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

+= が呼び出されます。 __iadd__ メソッド (それが存在する場合 -- フォールバックして __add__ が存在しない場合)、一方 + が呼び出されます。 __add__ メソッド 1 または __radd__ メソッドを使用する場合があります。 2 .

APIの観点から。 __iadd__ は、ミュータブルオブジェクトを変更するために使用されるはずです。 その場で (変異させたオブジェクトを返す)のに対し __add__ を返さなければなりません。 新しいインスタンス を使用します。 の場合 不変 オブジェクトの場合、どちらのメソッドも新しいインスタンスを返しますが __iadd__ は、新しいインスタンスを現在の名前空間に、古いインスタンスが持っていたのと同じ名前で配置します。 このため

i = 1
i += 1

はインクリメントされるようです。 i . 実際には、新しい整数を取得して、それを "on top" に代入します。 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]

最初の例では ba は同じオブジェクトを参照しますが +=b を変更すると、実際に b (そして a 結局のところ、同じリストを参照しているのです)。 しかし、2番目のケースでは、私が b = b + [1, 2, 3] というリストを取得します。 b が参照し、それを新しいリスト [1, 2, 3] . そして、連結されたリストを現在のネームスペースに次のように格納します。 b -- 何ら気にすることなく b はその前の行です。


1 式中 x + y もし x.__add__ が実装されていない場合、あるいは x.__add__(y)NotImplemented そして xy タイプが異なる であれば x + y を呼び出そうとします。 y.__radd__(x) . ということで

foo_instance += bar_instance

もし Foo は実装されていません。 __add__ または __iadd__ とすると、ここでの結果は

foo_instance = bar_instance.__radd__(bar_instance, foo_instance)

2 式中 foo_instance + bar_instance , bar_instance.__radd__ の前に試行されます。 foo_instance.__add__ もし のタイプは bar_instance の型のサブクラスです。 foo_instance (例 issubclass(Bar, Foo) ). その根拠は、以下の通りです。 Bar は、ある意味で Foo だから Bar をオーバーライドするオプションを取得する必要があります。 Foo の動作になります。