このページで解説している内容は、以下の YouTube 動画の解説で見ることができます。

【Python入門】代入式

代入式

 ここでは、Python 3.8で導入された「代入式」について解説します。代入文(x = 10 など)だけでなく、式の中で値を変数に代入できる代入式(x := 10)を使うことで、プログラムをより簡潔に記述できる場面があります。しかしながら、短く書けることだけがメリットではなく、場合によっては可読性を損なうこともあるため、使いどころを見極めることが大切です。以下で、代入式の基本的な書き方や由来、他言語との比較、そして具体例を順を追って紹介していきます。

プログラムのダウンロード

 「ダウンロード」から、JupyterLab で実行できるサンプルプログラムがダウンロードできます。ファイルは、ESET Endpoint Securityでウイルスチェックをしておりますが、ダウンロードとプログラムの実行は自己責任でお願いいたします。

1.代入式の概要

1.1. 代入式とは

 Python 3.8以降で使える「代入式」は、式の評価結果を変数に代入すると同時に、その値自体を式の結果として返す機能です。代入文との違いは以下のとおりです。

・代入文(=)

x = 10  # 変数xに10を代入する。式としての値は返さない。

・代入式(:=)

x := 10  # 変数xに10を代入し、さらに10を式の評価結果として返す。

 代入文は常に文(statement)扱いであり、if文やwhile文の条件式に直接書くことはできません。一方、代入式は“式”の一種なので、ifwhileなどの条件部分にも書ける点が特徴です。

1.2. セイウチ演算子の由来

 代入式は「:=」という記号を使うため、「セイウチ(ウォルラス)演算子」あるいは「ウォーラス演算子」と呼ばれることがあります。これは「:=」がセイウチの顔文字(横から見たときの目と牙)に見えることに由来しています。

「:=」とセイウチの関係

:=..
||

以下の表は、代入文と代入式の大まかな比較です。

種類記法返り値Pythonでの導入
代入文x = 10なし初期バージョンから
代入式x := 10代入した値(10)を返すPython 3.8以降

1.3. 代入式が導入された背景

 従来のPythonでは、変数に値を代入するためには、必ず代入文を使う必要がありました。しかし、たとえば「値を取得しつつ、その値を使って別の処理をしたい」という場合に、代入文とその後の処理とを分けて書かなければなりません。これではコードが煩雑になることがあります。
 そこで、Python 3.8で代入式が導入され、条件式やループの判定式などに直接代入を組み込めるようになり、コードを短く・読みやすく書ける可能性が広がりました。

2.他言語との比較

2.1. PascalとC系言語

 Pascal言語では、代入に:=を、比較に=を使います。一方、C/C++/Javaでは、代入には=、比較には==を使います。PythonはC系と同じく=で代入する文化ですが、代入式についてはPascal風の:=を採用しているため、両者の折衷のような位置づけといえるでしょう。

2.2. Pythonのセイウチ演算子

 Pythonが「:=」を使う理由は、代入と比較(==)とを混同しづらいようにするためとされています。可読性と機能を両立させるために、わざわざ新しい記法を導入したと捉えてよいでしょう。

2.3. ?:演算子とエルビス演算子

 Pythonでは使われませんが、?:演算子を「エルビス演算子」と呼ぶ言語(Kotlinなど)があります。こちらも、記号がエルヴィス・プレスリーの顔文字に似ていることから名付けられています。?:は条件分岐を短く書く際に使用される演算子ですが、Pythonでは三項演算子に相当する表記としてA if condition else Bを用いるため、?:は登場しません。

「?:」演算子とエルビスの関係

?:

3.使いどころと注意点

3.1. コードを短くしたい場合の利用

代入式を使うと、一行や一つの構文の中に代入から評価までをまとめられるため、以下のような利点があります。

  • 入力と判定を同時に行うループや条件分岐がスッキリ書ける。
  • 一時変数を省略できるので、行数を圧縮できる。

3.2. 読みやすさとのバランス

 ただし、過度に代入式を使うと、かえって処理内容が見えにくくなるケースもあります。たとえば、複数の代入式が混在すると、どのタイミングで何が代入されたのか把握しにくくなり、バグの原因になるかもしれません。
 そのため、「簡潔にできる」だけではなく「読みやすいかどうか」を踏まえて導入を検討するのが望ましいです。

4.プログラム例

 ここでは、代入式を使わない場合と使う場合、そしてクラスを用いた少し応用的な例を示します。サンプルプログラムとして「合計値を計算する」例を紹介します。

4.1. 代入式を使わない場合

 以下のコード例では、学校で集計する「テスト得点」を繰り返し入力し、合計点を表示するプログラムを想定しています。ユーザが'q'を入力したら終了します。

# 代入式を使わないバージョン
total_score = 0  # 合計点を0で初期化

while True:
    score_str = input("得点を入力してください(qで終了): ")
    if score_str == 'q':  # 'q'が入力されたらループを抜ける
        break
    total_score += int(score_str)  # 合計点に加算
    print("現在の合計:", total_score)

実行結果

得点を入力してください(qで終了):  70
現在の合計: 70
得点を入力してください(qで終了):  85
現在の合計: 155
得点を入力してください(qで終了):  90
現在の合計: 245
得点を入力してください(qで終了):  q
  • total_score = 0: 合計点を管理する変数を作り、初期値として0を代入しています。
  • while True: 無限ループを作成しています。
  • input("得点を入力してください(qで終了): "): 得点を入力してもらうための文字列入力。返された文字列をscore_strに代入しています。
  • if score_str == 'q':: 終了条件判定。ユーザが'q'と入力したらループを抜けるように設定。
  • total_score += int(score_str): 文字列を整数に変換し、合計点に加算しています。
  • print("現在の合計:", total_score): 現在の合計点を表示します。

4.2. 代入式を使う場合

 次に、上と同じ内容を代入式を使って書いてみます。while文の条件式内で入力を受け取り、その値が'q'であるかを同時に判定しています。

# 代入式を使うバージョン
total_score = 0

while (score_str := input("得点を入力してください(qで終了): ")) != 'q':
    print("現在の合計:", total_score := total_score + int(score_str))

実行結果

得点を入力してください(qで終了):  90
現在の合計: 90
得点を入力してください(qで終了):  65
現在の合計: 155
得点を入力してください(qで終了):  80
現在の合計: 235
得点を入力してください(qで終了):  q
  • while (score_str := input(...)) != 'q':
    input(...)からの返り値を変数score_strに代入しつつ、その結果が'q'と異なる限りループを続けています。
  • print("現在の合計:", total_score := total_score + int(score_str))
    total_score + int(score_str)の結果を変数total_scoreに代入し、同時にその値をprintで表示しています。
    ・累算代入演算子(+=)は代入式内では使えないため、total_score := total_score + int(score_str)のように記述しています。

 上記のように、代入式を利用すると、行数が大幅に減り、処理を一か所に集約できるため、コンパクトなコードになります。一方、どのタイミングで変数が更新されているのか分かりにくくなる可能性もあるため、扱うデータが増えて複雑になる場合は注意が必要です。

4.3. クラスを使った応用例

 ここでは、学校にある複数の科目ごとに得点を集計し、最終的な合計点を計算するサンプルを示します。任意の科目を追加入力していき、'q'でやめる形です。クラスを使うことで、科目名や得点をひとまとめに管理します。

class Subject:
    """科目の情報を管理するクラス"""
    def __init__(self, name, score=0):
        self.name = name
        self.score = score

    def add_score(self, additional):
        self.score += additional

# 代入式を使った科目の集計プログラム
subject_list = []
while (name := input("科目名を入力してください(qで終了): ")) != 'q':
    if (score_str := input(f"{name}の得点を入力してください(qで終了): ")) == 'q':
        break
    subject = Subject(name, int(score_str))
    subject_list.append(subject)

# 最終的な合計点を表示
total_score = sum(sub.score for sub in subject_list)
print("登録された科目と得点:")
for sub in subject_list:
    print(f"{sub.name}: {sub.score}点")

print("全科目の合計点:", total_score)

実行結果

科目名を入力してください(qで終了):  英語
英語の得点を入力してください(qで終了):  60
科目名を入力してください(qで終了):  数学
数学の得点を入力してください(qで終了):  80
科目名を入力してください(qで終了):  国語
国語の得点を入力してください(qで終了):  70
科目名を入力してください(qで終了):  q
登録された科目と得点:
英語: 60点
数学: 80点
国語: 70点
全科目の合計点: 210
  • class Subject:
    科目の名前と得点を持つクラスです。コンストラクタで科目名と得点を受け取り、それらをインスタンス変数に保存します。
  • while (name := input(...)) != 'q':
    代入式を使って、科目名を受け取りつつ'q'でない限りループを続けます。
  • if (score_str := input(...)) == 'q':
    科目名のあとの得点入力で'q'が来たら、すぐにループを終了するようにしています。
  • Subject(name, int(score_str))
    入力された科目名と得点をまとめてSubjectインスタンスを作り、リストに追加します。
  • 最後に、登録された科目すべてを表示し、合計点を算出して表示します。

 このようにクラスを絡めても代入式は有効に使えますが、記述が長くなる場合は代入文との使い分けを考慮して、コードの可読性を維持することが大切です。

まとめ

 Python 3.8から導入された代入式は、式の評価と変数代入を同時に行える便利な機能です。コードを短く書けるだけでなく、入力や計算の結果をそのまま条件式に渡す際などに役立ちます。一方で、複数の代入式が絡むと読みにくくなることもあります。
 プログラムがシンプルに、かつ意図が分かりやすくなるなら代入式を使い、可読性を落としそうな場合や混乱を招きそうな場合は従来の代入文を使うといったように、使いどころを選んで活用してみてください。読みやすいコードを書くことは、チーム開発や将来的なメンテナンスにも大きく貢献します。