3.

Python 代入演算子|複合代入・アンパック・セイウチ演算子(:=)の使い方

編集
この記事の要点
  • Python の代入は「値のコピー」ではなくオブジェクトへの名前付け
  • 複合代入は += -= *= /= //= %= **= &= |= ^= <<= >>=
  • リストの x += [1]その場で書き換えx = x + [1]新しいリストを作る。共有していると結果が変わる
  • アンパック代入 a, b = b, a で一時変数なしの入れ替えができる
  • :=(セイウチ演算子, Python 3.8+)は式の中で代入する。while (line := f.readline()): の形が定番

代入は「箱に入れる」ではない

Python の = は、右辺のオブジェクトに左辺の名前を結び付ける操作です。値がコピーされるわけではありません。

a = [1, 2, 3]
b = a            # 同じリストに別名を付けただけ
b.append(4)
print(a)         # [1, 2, 3, 4]   ← a も変わる

# 別物にしたいならコピーする
c = a.copy()     # または list(a) / a[:]
c.append(5)
print(a, c)      # [1, 2, 3, 4] [1, 2, 3, 4, 5]

# 入れ子は copy でも内側が共有される
import copy
d = copy.deepcopy(a)   # 完全に独立させたいとき

複合代入の一覧

演算子意味
+=加算 / 連結x += 1
-= *=減算 / 乗算x *= 2
/=除算(float になる)x /= 2
//= %=切り捨て除算 / 剰余x //= 2
**=べき乗x **= 2
&= |= ^=ビット AND / OR / XORflags |= MASK
<<= >>=シフトx <<= 1

Python には ++ / -- はありません。x += 1 と書きます。x++ は構文エラー、++x は「単項プラスを 2 回」と解釈されて何も起きません。

+== x + は同じではない

a = [1, 2]
b = a
a += [3]          # その場で拡張(a.extend([3]) と同じ)
print(a, b)       # [1, 2, 3] [1, 2, 3]   ← b も変わる

a = [1, 2]
b = a
a = a + [3]       # 新しいリストを作って a に付け替え
print(a, b)       # [1, 2, 3] [1, 2]      ← b は元のまま

タプルや文字列のような不変オブジェクトでは、+= も必ず新しいオブジェクトを作るのでこの違いは出ません。

複数代入とアンパック

x = y = 0                 # 同じ値を同時に
a, b = 1, 2               # タプルのアンパック
a, b = b, a               # 入れ替え(右辺が先に評価される)
print(a, b)               # 2 1

first, *rest = [1, 2, 3, 4]
print(first, rest)        # 1 [2, 3, 4]

head, *mid, tail = [1, 2, 3, 4, 5]
print(head, mid, tail)    # 1 [2, 3, 4] 5

for i, name in enumerate(["a", "b"]):
    print(i, name)        # 0 a / 1 b

# 使わない値は _ に入れる慣習
_, important = ("捨てる", "使う")

x = y = []同じ空リストを 2 つの名前で共有します。別々に使いたいなら x, y = [], [] と書いてください。

セイウチ演算子(:=)

Python 3.8 で入った、式の中で代入するための演算子です。値を使い回したいが、そのために行を増やしたくないときに使います。

# 読み込みながら終端を判定する
with open("data.txt") as f:
    while (line := f.readline()):
        print(line.rstrip())

# 計算結果を条件と本体の両方で使う
data = [1, 2, 3, 4, 5]
if (n := len(data)) > 3:
    print(f"{n} 件は多い")

# 内包表記で中間結果を再利用する
words = ["apple", "kiwi", "banana"]
long_upper = [u for w in words if len(u := w.upper()) > 4]
print(long_upper)   # ['APPLE', 'BANANA']

括弧が必要な場面が多く、読みにくくなりがちです。同じ値を 2 回書くのを避けられるときだけ使うのが無難です。

グローバル変数への代入

count = 0

def bad():
    # count += 1
    # UnboundLocalError: 関数内で代入があると全体がローカル扱いになる
    pass

def good():
    global count
    count += 1

good()
print(count)   # 1

入れ子関数で外側のローカル変数に代入したい場合は nonlocal を使います。ただし、どちらも多用すると追いにくくなるため、値を返す設計にできないか先に検討してください。

関連

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 算術演算子
  2. 文字列演算子
  3. 代入演算子
  4. 比較演算子
  5. 論理演算子
  6. ビット演算子

最近更新/作成されたページ