Pythonのタイプヒントを使用していると、「この変数は整数が入ることもあれば、文字列が入ることもある」といったケースや、「どんな型のデータが来るか特定できない」といったケースに遭遇します。
このような柔軟な型定義を行うために、Pythonには Union型(または | 演算子) と Any型 が用意されています。
この記事では、これら2つの使い方と、それぞれの適切な利用シーンについて解説します。
1. 複数の型を許容する (Union / |)
変数が「AまたはB」といった複数の型のいずれかを取りうる場合に使用します。
Python 3.10以降の記法 (| 演算子)
Python 3.10からは、パイプ記号 | を使うことで、非常に直感的に「または」を表現できるようになりました。現在はこちらの記法が推奨されています。
構文: 型A | 型B
使用例: ユーザーIDとして、整数(例: 101)と文字列(例: "user_01")の両方を受け付ける関数を定義します。
def get_user_name(user_id: int | str) -> str:
"""
ユーザーID(整数または文字列)を受け取り、名前を返す関数
"""
if isinstance(user_id, int):
return f"User(No.{user_id})"
else:
return f"User(ID:{user_id})"
# --- 実行 ---
print(get_user_name(500)) # int を渡す
print(get_user_name("admin")) # str を渡す
実行結果:
User(No.500)
User(ID:admin)
Python 3.9以前の記法 (Union)
古いバージョンのPythonを使用している場合は、標準ライブラリ typing モジュールから Union をインポートして使用します。意味は | と全く同じです。
構文: Union[型A, 型B]
from typing import Union
# 整数、浮動小数点数、またはNoneが入る可能性がある変数
# Python 3.10以降の int | float | None と等価
measurement_value: Union[int, float, None] = 12.5
print(f"測定値: {measurement_value}")
2. 任意の型を許容する (Any)
「どのような型でも受け入れる」ことを明示したい場合は、typing モジュールの Any を使用します。
Any を指定すると、その変数に対する型チェックは実質的に無効化されます。動的なデータを扱う場合や、型を特定するのが困難な過渡期に使用されます。
構文: Any
使用例: どんなデータでも受け取り、その型と中身をログに出力する汎用的な関数を定義します。
from typing import Any
def log_debug_info(data: Any) -> None:
"""
あらゆる型のデータを受け取り、情報を出力する
"""
print(f"[Debug] Type: {type(data)} | Value: {data}")
# --- 実行 ---
log_debug_info(1024) # int
log_debug_info("System Error") # str
log_debug_info([1, 2, 3]) # list
log_debug_info({"key": "value"}) # dict
実行結果:
[Debug] Type: <class 'int'> | Value: 1024
[Debug] Type: <class 'str'> | Value: System Error
[Debug] Type: <class 'list'> | Value: [1, 2, 3]
[Debug] Type: <class 'dict'> | Value: {'key': 'value'}
Any使用上の注意
Any は便利ですが、多用すると「型ヒントによるエラー検知」というメリットが失われてしまいます。
可能な限り int | str のように型を絞り込み、どうしても型を特定できない場合や、ライブラリの仕様で型が不明な場合にのみ Any を使用することが推奨されます。
まとめ
int | str: 「整数または文字列」のように、複数の候補がある場合に使用します(Python 3.10以降)。Union[int, str]: 上記と同じ意味の、古いバージョン向けの記法です。Any: 「どんな型でもよい」場合に使用します。型チェックを無効化するため、使用は必要最小限に留めるべきです。
