SIGMA-SE Math & Tech Library

SIGMA-SE Math & Tech Library


数学と情報技術をテーマに、書籍や教材だけではつかみにくい考え方を具体例とともに簡潔にわかりやすく伝える解説サイトです。
技術の歴史や背景、関連知識の整理、学習のための覚書や要約記事も掲載しています。

Python - 複合代入演算子:値の更新を短く書く方法

概要

Pythonの複合代入演算子を使った値の更新を整理する。

数値の加算・減算などを通常の代入と対応させた後、listの+=と+を比較する。更新後の値が同じでも別の変数への影響が異なる理由を追い、共有しているデータを変更するかどうかで書き方を選ぶ。listの比較例はPython 3.12.2で確認。

この記事の構成

各複合代入演算子の使い方と実装サンプル

複合代入演算子の種類

代入演算子には、一般的な右辺から左辺へ代入する代入演算子(=)と右辺から左辺へ算術演算子を添えて代入する複合代入演算子(+=, -=など)がある。

  • 複合代入演算子一覧
    演算子 使用例 説明
    += a += b a に b を加算し、結果を a に代入。
    -= a -= b a から b を減算し、結果を a に代入。
    *= a *= b a に b を乗算し、結果を a に代入。
    /= a /= b a を b で除算し、結果を a に代入。
    //= a //= b a を b で切り下げ除算し、結果を a に代入。
    %= a %= b a を b で割った剰余を a に代入。
    **= a **= b a の b 乗を a に代入。

a += bはa = a + bに近い計算だが、完全に同一ではない。複合代入は左辺を一度だけ評価し、型が対応していれば同じオブジェクトをその場で変更する。この違いはlistなどのミュータブルな型や、添字・属性を左辺にした場合に現れる。

以降、実装サンプルを対話モード(インタプリタ)で解説する。

※ int型は任意精度であり、float型とcomplex型の有限値の範囲は実装環境の浮動小数点形式に依存する。詳しくは下記を参考。

加算(+=)・減算(-=)

  • 加算(+=)
    ※ 数値型ではa = a + bに近い結果となるが、複合代入は左辺を一度だけ評価する。

    $ python
        >>> # int型の 2 に 3 を加算複合代入
        >>> int_a = 2
        >>> int_a += 3
        >>> print(int_a)
        5
        >>> # float型の 3.5 に 3.6 を加算複合代入
        >>> float_a = 3.5
        >>> float_a += 3.6
        >>> print(float_a)
        7.1
        >>> # complex型の 4 + 4j に 5 + 5j を加算複合代入
        >>> complex_a = 4 + 4j
        >>> complex_a += 5 + 5j
        >>> print(complex_a)
        (9+9j)
        >>>
    
  • listの+=と+を別の変数から比べる
    どちらもitemsへ30を追加するが、同じlistを参照しているobservedから見た結果は異なる。

    items = [10, 20]
    observed = items
    items += [30]
    print(items, observed, items is observed)
    
    items = [10, 20]
    observed = items
    items = items + [30]
    print(items, observed, items is observed)
    
    [10, 20, 30] [10, 20, 30] True
    [10, 20, 30] [10, 20] False
    

    listの+=は元のlistを変更するため、同じオブジェクトを参照するobservedにも追加後の内容が見える。+は連結した新しいlistを作り、その参照をitemsへ代入する。observedは元のlistを参照し続ける。

    共有中のlistを更新したい場合は+=やextend()を使える。連結前のlistを残したい場合は+で新しいlistを作る。ただし新しい外側のlistを作っても入れ子の要素までは複製されない。コピーの範囲はlist・dictの記事を参照。

    整数の+=は元の整数オブジェクトを書き換えない。複合代入がその場で変更するかどうかは型に依存するため、短く書き換える際も対象の型と共有の有無を確かめる。

  • 減算(-=)
    以下の組込み数値型と単純な変数の例では、a = a - bと同じ計算結果になる。

    $ python
        >>> # int型の 5 に 3 を減算複合代入
        >>> int_a = 5
        >>> int_a -= 3
        >>> print(int_a)
        2
        >>> # float型の 5.0 に -5.9 を減算複合代入
        >>> float_a = 5.0
        >>> float_a -= -5.9
        >>> print(float_a)
        10.9
        >>> # complex型の 5 + 5j に 10 - 10j を減算複合代入
        >>> complex_a = 5 + 5j
        >>> complex_a -= 10 - 10j
        >>> print(complex_a)
        (-5+15j)
        >>>
    

乗算(*=)・除算(/=・//=)・剰余(%=)

  • 乗算(*=)
    以下の組込み数値型と単純な変数の例では、a = a * bと同じ計算結果になる。

    $ python
        >>> # int型の 2 に 3 を乗算複合代入
        >>> int_a = 2
        >>> int_a *= 3
        >>> print(int_a)
        6
        >>> # float型の 2.5 に -3.0 を乗算複合代入
        >>> float_a = 2.5
        >>> float_a *= -3.0
        >>> print(float_a)
        -7.5
        >>> # complex型の 5 + 2j に 2 - 5j を乗算複合代入
        >>> complex_a = 5 + 2j
        >>> complex_a *= 2 - 5j
        >>> print(complex_a)
        (20-21j)
        >>>
    
  • 除算(/=)
    以下の組込み数値型と単純な変数の例では、a = a / bと同じ計算結果になる。

    $ python
        >>> # int型の 6 に 2 を除算複合代入
        >>> int_a = 6
        >>> int_a /= 2
        >>> print(int_a)
        3.0
        >>> # float型の 5.5 に -0.5 を除算複合代入
        >>> float_a = 5.5
        >>> float_a /= -0.5
        >>> print(float_a)
        -11.0
        >>> # complex型の 2 + 2j に 1 + 1j を除算複合代入
        >>> complex_a = 2 + 2j
        >>> complex_a /= 1 + 1j
        >>> print(complex_a)
        (2+0j)
        >>>
    
  • 切り下げ除算(//=)
    以下の組込み数値型と単純な変数の例では、a = a // bと同じ計算結果になる。

    $ python
        >>> # int型の 11 に 3 を除算(//)複合代入
        >>> int_a = 11
        >>> int_a //= 3
        >>> print(int_a)
        3
        >>> # float型の 3.3 に 0.2 を除算(//)複合代入
        >>> float_a = 3.3
        >>> float_a //= 0.2
        >>> print(float_a)
        16.0
        >>> # complex型の除算(//)はできない
        >>> complex_a = 3 + 3j
        >>> complex_a //= 2 + 2j
        Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        TypeError: unsupported operand type(s) for //: 'complex' and 'complex'
        >>>
    
  • 剰余(%=)
    以下の組込み数値型と単純な変数の例では、a = a % bと同じ計算結果になる。

    $ python
        >>> # int型の 9 に 2 を剰余複合代入
        >>> int_a = 9
        >>> int_a %= 2
        >>> print(int_a)
        1
        >>> # float型の 6.5 に 2 を剰余複合代入
        >>> float_a = 6.5
        >>> float_a %= 2
        >>> print(float_a)
        0.5
        >>> # complex型に剰余はできない
        >>> complex_a = 3 + 3j
        >>> complex_a %= 2
        Traceback (most recent call last):
        File "<stdin>", line 1, in <module>
        TypeError: unsupported operand type(s) for %: 'complex' and 'int'
        >>>
    

    ※ 例外メッセージの文言はPythonのバージョンで変わる場合があるが、複素数に // や % を適用すると TypeError になる点が重要。

べき乗(**=)

以下の組込み数値型と単純な変数の例では、a = a ** bと同じ計算結果になる。

$ python
    >>> # int型の 2 に 4 をべき乗複合代入
    >>> int_a = 2
    >>> int_a **= 4
    >>> print(int_a)
    16
    >>> # float型の 2.5 に 2 をべき乗複合代入
    >>> float_a = 2.5
    >>> float_a **= 2
    >>> print(float_a)
    6.25
    >>> # complex型の 2 + 2j に 2 をべき乗複合代入
    >>> complex_a = 2 + 2j
    >>> complex_a **= 2
    >>> print(complex_a)
    8j
    >>>

まとめ

  • 複合代入は演算と代入をまとめ、左辺を一度だけ評価する。
  • listの+=は元のlistを変更する。+で連結して再代入すると外側のlistは別オブジェクトになり、元のlistを参照する変数へ連結結果は伝わらない。
  • その場で変更するかどうかは型に依存する。通常の代入を短く書き換える前に型と参照共有を確認する。

参考文献

この記事を共有
Xで共有 Facebookで共有 LINEで共有



Copyright SIGMA-SE All Rights Reserved.
s-hama@sigma-se.jp