Contents
背景と実装経緯
| 項目 | 内容 |
|---|---|
| PEP 572 | 「代入式 (assignment expression)」として := を提案。目的は「式の中で変数に値を束縛できるようにする」こと。 |
| 実装バージョン | Python 3.8 から正式に組み込まれ、以降の全リリースでも利用可能。 |
| 公式ドキュメント | https://peps.python.org/pep-0572/ 、https://docs.python.org/3/reference/expressions.html#assignment-expressions |
従来は代入はステートメント (=) に限られ、if, while, リスト内包表記などの式の中へ持ち込むことができませんでした。PEP 572 はこの制約を緩和し、評価と同時に変数への束縛を 1 行で書ける構文を提供します。
基本構文と動作
|
1 2 3 4 |
# 一般的な形 if (n := len(items)) > 0: print(f"{n} 件のアイテムがあります") |
- 左辺は 単一の変数名(または属性参照)に限られます。
:=の右側には任意の式を書け、右辺が評価された結果が左辺へ代入されます。- 代入式全体は右辺の評価値を 式として返す ため、他の演算子や関数呼び出しの引数に組み込むことが可能です。
例:平均と合計を同時に取得
|
1 2 3 |
total = (s := sum(values)) / len(values) # s に合計が格納され、average が total に入る print(f"合計={s}, 平均={total}") |
実務での典型的な活用シーン
1. 条件式内での代入
|
1 2 3 4 |
# CSV のヘッダー行を取得しつつ、空でなければ処理へ進む if (header := next(csv_reader, None)): process_header(header) |
- メリット
- 「取得」→「判定」の 2 手順が 1 行に収まる。
- 再度同じ変数を参照できるので、余計な関数呼び出しや一時変数の増加を防げる。
2. 内包表記での一時変数作成
|
1 2 3 4 5 6 7 |
# 正規表現検索結果をキーに、マッチオブジェクトも保持した辞書を生成 matched = { m.group(): (m := pattern.search(m.group())) # ← 代入式で m を再利用 for line in lines if (m := pattern.search(line)) } |
- ポイント
- ループ本体がシンプルになるだけでなく、外部スコープに余計な変数を残さない。
3. ログ・API 解析などの「取得 → 判定」パターン
| シナリオ | 従来コード例 | walrus 版 |
|---|---|---|
| CSV 行の読み込みと空行除去 | row = next(reader); if row: … (2 行) |
if (row := next(reader, None)): (1 行) |
| ログからエラーメッセージ抽出 | line = f.readline(); if "ERROR" in line: |
if "ERROR" in (line := f.readline()): |
| API の JSON から必須キー確認 | data = resp.json(); if "id" in data: |
if "id" in (data := resp.json()): |
- 効果
- 再取得忘れによるバグを防止。
- 条件部が簡潔になることで可読性が向上。
注記:上記の数値的な「行数削減率」や「処理時間短縮率」は環境依存が大きく、公式に測定されたデータはありません。実際のプロジェクトでベンチマークを取ることを推奨します。
演算子の優先順位と可読性ガイドライン
正しい優先順位表(Python 3.12 まで共通)
| 優先順位 (高 → 低) | 演算子・構文 |
|---|---|
| 1 | ()、[]、.、属性参照、呼び出し、サブスクリプト |
| 2 | ** |
| 3 | +x, -x, ~x(単項) |
| 4 | * / // % @ |
| 5 | + - |
| 6 | << >> |
| 7 | & |
| 8 | ^ |
| 9 | \| |
| 10 | 比較演算子 < > <= >= == != is is not in not in |
| 11 | not |
| 12 | and |
| 13 | or |
| 14 | 条件式 x if y else z |
| 15 | lambda |
| 16 | 代入式 :=(最も低い) |
公式ドキュメント: https://docs.python.org/3/reference/expressions.html#operator-precedence
括弧が必要になる典型例
|
1 2 3 4 5 6 7 |
# 正しい書き方(代入式は最下位なので、比較や論理演算子の前に括弧を付ける) if (n := func()) > 0 and n < limit: ... # 括弧が無いと SyntaxError になる例 # if n := func() > 0 and n < limit: # ← 代入式が比較より後に評価されないためエラー |
可読性を保つための実践的指針
| 指針 | 内容 |
|---|---|
| 1 行に 1 つの代入 | 条件部で複数の代入式を連ねると読みにくくなる。必要なら事前代入へ分割する。 |
| 長い条件は分割 | if (data := fetch()).status == "ok" and (user := data.user).active: のように 2 つ以上の代入が混在すると可読性が低下。次のように書く方が安全。data = fetch() if data.status == "ok": user = data.user if user.active: |
| 変数名は意味を持たせる | tmp, x などの抽象的な名前は避け、line, payload, match_obj のように何が入っているか示す。 |
| チーム規約への組み込み例 | 代入式は条件部だけで使用し、スコープ外へ露出させない、複数代入が必要な場合は別行に分割する などを PEP 8 に追記しておくと良い。 |
使用上の制限・非推奨パターン
| 非推奨例 | 問題点 | 推奨代替 |
|---|---|---|
if (a := (b := func1()) + func2(b)) > 0: |
ネストが深く、どの変数が何に使われているか一目で分からない。 | python b = func1(); a = b + func2(b) |
x = y if (z := cond()) else w(三項式内) |
条件と代入が混在し、可読性が著しく低下。 | python z = cond(); x = y if z else w |
while (data := fetch()) and (item := data.get('key')): |
1 行に複数の代入式が入り込み、ループ本体が不透明になる。 | python while True: data = fetch() if not data: break item = data.get('key') … |
バージョン互換性
- Python 3.8 以上が必須 –
:=はそれ以前のインタプリタでは構文エラーになります。 - 古い環境向けのフォールバック例
|
1 2 3 4 5 6 7 8 9 10 |
import sys if sys.version_info >= (3, 8): if (cnt := len(items)) > 0: print(f"{cnt} 件あります") else: # Python 3.7 以前 cnt = len(items) if cnt > 0: print(f"{cnt} 件あります") |
- バックポートは公式には提供されていません。したがって、プロジェクトで最低限の対応バージョンを
>=3.8と定めるか、上記のようにコード分岐させる必要があります。
まとめと実装へのステップ
- PEP 572 の意図 – 式内部で代入できることで「取得 → 判定」や「一時変数を作りながらリスト内包表記を書く」ケースがシンプルになる。
- 基本構文 –
target := expressionが左辺に単一の名前、右辺に任意の式を取ることを覚える。 - 実務での活用例
if/while条件部での代入 → 余計な行数削減とバグ防止。- 内包表記内での一時変数生成 → スコープ汚染を抑えつつコードが簡潔に。
- 大量データ処理(CSV、ログ、API)で「取得+判定」を 1 行で実装。
- 優先順位 – 代入式は最も低い位置にあるため、必ず括弧で囲んで評価順序を明示する。
- 可読性ガイドライン
- 条件部に代入は 1 個まで。
- 複雑なロジックは事前代入へ分割。
- 変数名は具体的にし、チーム規約で統一する。
- 互換性対策 – Python 3.8 未満を対象とする場合はバージョンチェックと代替コードを用意する。
次のアクション
1. プロジェクトの最小サポートバージョンが 3.8 以上であることを確認。
2. コードベースのif/while条件部をレビューし、代入式導入可能箇所を洗い出す。
3. チームのコーディング規約に「walrus 演算子は条件部でのみ使用」や「1 行に代入は 1 個まで」などのルールを追加。
4. 必要ならば、Python 3.7 以下向けのフォールバック実装をテストケースに組み込む。
以上のポイントを踏まえて walrus 演算子 を適切に取り入れれば、コードは 簡潔さと可読性のバランスが取れたもの になるでしょう。