Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

Python の累算代入は演算してから代入しているのではない

More than 3 years have passed since last update.

はまったこと

Python のコレクションの要素に累算代入演算子を使ったところ、想定外の動作をしたので、メモしておきます。

デフォルトの設定を保持する辞書 default_settings に追加の設定 additional_settings をマージしてから特定の設定をいじる処理をしていました。

>>> # 以下の2変数は変更したくない(定数的なものを想定)
>>> default_settings = {'a': 1, 'b': [0, 1]}
>>> additional_settings = {'a': 10, 'c': 'hoge'}
>>> 
>>> settings = dict(default_settings, **additional_settings)
>>> settings
{'a': 10, 'b': [0, 1], 'c': 'hoge'}
>>> 
>>> # 'list' に 2, 3 を追加
>>> # default_settings が変更されたら困るので extend でなく、+ 演算子を使う
>>> settings['b'] += [2, 3]
>>> settngs  # こっちは OK
{'a': 10, 'b': [0, 1, 2, 3], 'c': 'hoge'}
>>> default_settings  # こっちは NG。なぜか 'b' が書き換っている!!
{'a': 1, 'b': [0, 1, 2, 3]}

なぜそうなるか

Python のドキュメントを見ると以下のように書いてあります。

x += 1 のような累算代入式は、 x = x + 1 のように書き換えてほぼ同様の動作にできますが、厳密に等価にはなりません。累算代入の方では、 x は一度しか評価されません。また、実際の処理として、可能ならば インプレース (in-place) 演算が実行されます。これは、代入時に新たなオブジェクトを生成してターゲットに代入するのではなく、以前のオブジェクトの内容を変更するということです。

つまり、上の例ではあえて extend でなく + としたが、+= と書くと + ではなく extend と同じ動作をするということです。よって正しくは以下のようにしなくてはいけません。

>>> default_settings = {'a': 1, 'b': [0, 1]}
>>> additional_settings = {'a': 10, 'c': 'hoge'}
>>> 
>>> settings = dict(default_settings, **additional_settings)
>>> settings
{'a': 10, 'b': [0, 1], 'c': 'hoge'}
>>> 
>>> settings['b'] = settings['b'] + [2, 3]
>>> settngs
{'a': 10, 'b': [0, 1, 2, 3], 'c': 'hoge'}
>>> default_settings
{'a': 1, 'b': [0, 1]}

何、その仕様???

ちなみに C, C++, Java, C#, Ruby などを調べましたが、こんな奇妙な仕様にはなっていないようです。(ただし、Ruby のメンバに対する = は代入(メンバへのバインド)ではなくメソッド呼び出しなので、Ruby だけちょっと事情が異なりますが。)

YuoMamoru@github
合同会社レスタス 代表。 起業しました。 これまでは業務系システムやら、Webシステムやら金融系の情報系システムやらをやってました。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away