変数、関数に対する型アノテーション

Pythonは柔軟な動的型付け言語ですが、コードの可読性を高め、型に関するバグを未然に防ぐために型アノテーション(Type Annotation)を利用することができます。アノテーションとは「注釈」という意味であり、変数や関数の引数、戻り値に対して「どのようなデータ型を期待しているか」をソースコードに注釈として刻み込むことができます。このガイドでは、変数や関数に対する具体的な書き方と、実務でよく使う応用的なアノテーションについて解説します。
変数に対する型アノテーション
変数に対する型アノテーションは、その変数がどのようなデータを持つべきかを明示するために使用します。変数名の後ろにコロン : を打ち、続けて型名を記述します。
# 変数に対する型アノテーションの例
name: str = "Alice"
age: int = 25
is_active: bool = True
print(name) # "Alice"
print(age) # 25
print(is_active) # True
この例では、name が文字列(str)、age が整数(int)、is_active がブール型(bool)であることを示しています。
関数に対する型アノテーション
関数に対しても型アノテーションを使うことで、引数や戻り値の型を明示できます。これは、関数がどのような入力を受け取り、どのような結果を出力するのか(関数の仕様書)をコード上で明確にするために非常に有用です。
# 関数に対する型アノテーションの例
def add_numbers(x: int, y: int) -> int:
return x + y
result = add_numbers(5, 10)
print(result) # 15
この例では、引数 x と y が整数型であり、関数が最終的に返す戻り値(-> の先)も整数型であることが一目で分かります。
複数の引数を持つ関数の型アノテーション
複数の異なる型が混ざる関数であっても、引数ごとに個別にアノテーションを付けることができます。デフォルト値(初期値)を設定する場合の書き方も合わせて押さえておきましょう。
# 複数の引数と、デフォルト値がある場合の型アノテーション
def greet(name: str, age: int, message: str = "Hello") -> str:
return f"{message}, {name}. You are {age} years old."
# デフォルト値を活かして呼び出し
print(greet("Bob", 30)) # "Hello, Bob. You are 30 years old."
この関数では、name が文字列、age が整数、デフォルト値を持つ message が文字列であり、戻り値が文字列であることを示しています。引数にデフォルト値を指定する場合は、型名 = 値 の順で記述します。
複雑なデータ構造に対する型アノテーション(モダンな書き方)
リストや辞書といった、中に複数の要素を含むコレクション型に対しても詳細にアノテーションを適用できます。過去のPython(3.8以前)では typing モジュールから大文字の List や Dict をインポートする必要がありましたが、現在のモダンなPython(3.9以降)では標準の小文字(list や dict)をそのまま使用するシンプルな書き方が推奨されています。
# Python 3.9以降の推奨される書き方(標準のコレクション型を使用)
numbers: list[int] = [1, 2, 3, 4, 5] # 整数のリスト
students: dict[str, int] = {"Alice": 25, "Bob": 30} # キーが文字列、値が整数の辞書
print(numbers) # [1, 2, 3, 4, 5]
print(students) # {'Alice': 25, 'Bob': 30}
# ※古いPython 3.8以前の環境コードを保守する場合は、以下のように書かれていました
# from typing import List, Dict
# numbers: List[int] = [1, 2, 3, 4, 5]
このように list[int] や dict[str, int] と記述することで、データ構造の内側の型までエディタや静的解析ツールに伝えることができます。
一歩進んだ応用:複数の型を許容する(Union / | 演算子)
実務では「整数、または浮動小数点数のどちらを受け取っても良い」というように、複数の型を認めたいケースがあります。モダンなPython(3.10以降)では、パイプ記号 | を使うことで、複数の型をスマートに並べて指定(Union型)することができます。
# int型、またはfloat型を許容するアノテーション(Python 3.10以降)
def process_score(score: int | float) -> str:
return f"Score: {score}"
print(process_score(95)) # 整数を渡してもOK
print(process_score(88.5)) # 小数を渡してもOK
型アノテーションの注意点と効果的な運用
型アノテーションを導入するにあたり、以下の設計思想を理解しておくことが大切です。
- 「ヒント」と「アノテーション」の違い: 厳密には、コードに記述された注釈そのものを「アノテーション」、それを利用してエディタやツールに型を伝える仕組み全体を「型ヒント」と呼びますが、実務ではほぼ同じ意味の言葉として使われています。
- 強制力はない: 何度も強調する通り、Pythonの実行エンジンはアノテーションを完全に無視して動作します。間違った型が渡されても実行時には検知できないため、厳格なチェックには
mypyなどの外部型チェッカーを開発フロー(CIなど)に組み込む必要があります。 - 段階的な導入が可能: すべてのコードに書く必要はありません。まずはバグが起きやすい「重要な関数の引数・戻り値」からピンポイントでアノテーションを付けていく、といった柔軟な運用が可能です。
まとめ
型アノテーションは、Pythonならではの「素早く、柔軟にコードが書ける」というメリットを邪魔することなく、チーム開発や大規模化に耐えうる「堅牢さ」をプラスできる優れた仕組みです。特にモダンなPython 3.9以降の組み込み型(list[...])や、Python 3.10以降の | 演算子による複数型指定などを組み合わせることで、非常にスマートで美しいコードを記述できます。関数の入出力を明示する習慣を身につけ、バグの少ないクリーンなPythonコードを目指しましょう。