Pythonの型ヒント:コレクション型とOptional型の使い方
前回は、型ヒントの基本的な利用方法について解説した。
今回は、リストや辞書などのコレクション型と、Noneを許可するOptional型について詳しく解説していく。
コレクション型の型ヒント
コレクション型とは、複数の値をまとめて扱うデータ型のことだ。Python では list、set、tuple、dict などがこれに該当する。
リスト(list)の型ヒントは `list[型]` という形で書く。
names: list[str] = ["Alice", "Bob", "Charlie"] # 文字列のリスト
scores: list[int] = [85, 92, 78, 90] # 整数のリスト
セット(set)の型ヒントは `set[型]` で表現する。
unique_names: set[str] = {"Alice", "Bob", "Charlie"} # 文字列のセット
prime_numbers: set[int] = {2, 3, 5, 7, 11, 13} # 整数のセット
タプル(tuple)の型ヒントには2つの書き方がある。
# 固定長タプル(要素数と各位置の型が決まっている)
person: tuple[str, int, bool] = ("Alice", 25, True)
coordinates: tuple[float, float] = (10.5, 20.3)
# 可変長タプル(同じ型の要素が任意個)
rgb_colors: tuple[int, ...] = (255, 128, 64, 32)
辞書(dict)の型ヒントは `dict[キー型, 値型]` で書く。
ages: dict[str, int] = {"Alice": 25, "Bob": 30, "Charlie": 28}
# ネストした型も指定可能
hobbies: dict[str, list[str]] = {
"Alice": ["reading", "swimming"],
"Bob": ["gaming", "cooking"]
}
Optional型でNoneを安全に扱う
実際のプログラムでは、値が存在しない場合を表現するためにNoneを使うことがよくある。Optional型を使えば、Noneになる可能性がある変数を型安全に扱える。
from typing import Optional
user_name: Optional[str] = None # 文字列またはNone(「str | None」でも可)
user_id: Optional[int] = 42 # 整数またはNone(「int | None」でも可)
関数の戻り値でOptional型を使う例を見てみよう。
def find_user_by_email(email: str) -> Optional[str]: # 「str | None」でも可
users = {"alice@example.com": "Alice", "bob@example.com": "Bob"}
return users.get(email) # 見つからない場合はNone
result = find_user_by_email("charlie@example.com")
# Noneチェックが必要(ないとVSCodeで警告が表示される)
if result is not None:
print(f"Found user: {result}")
else:
print("User not found")
「is not None」のチェックがないとき、Noneだと実行ができない処理の場合に以下のように警告が表示される。

Python 3.10以降では、Optional[str] の代わりに str | None という書き方もできる。どちらも同じ意味だが、新しい書き方の方が簡潔だ。
実践的な例:ユーザー検索機能
実際のコードで型ヒントがどのように活用されるか見てみよう。
from typing import Optional
def find_user_by_id(users: list[dict[str, str]], user_id: str) -> dict[str, str] | None:
for user in users:
if user.get('id') == user_id:
return user
return None
users = [
{'id': '001', 'name': '田中'},
{'id': '002', 'name': '佐藤'},
]
user = find_user_by_id(users, '001')
if user is not None:
print(user['name']) # 田中
この例では、list[dict[str, str]] という複雑な型ヒントを使っている。これは「文字列をキーと値に持つ辞書のリスト」という意味だ。
クラスを使った型ヒントの例
より複雑な例として、クラスを使った商品分類システムを見てみよう。
class Product:
def __init__(self, name: str, category: str):
self.name = name
self.category = category
items = [
Product(name='ノートPC', category='電子機器'),
Product(name='マウス', category='電子機器'),
Product(name='コーヒー', category='飲料'),
]
def group_items_by_category(items: list[Product]) -> dict[str, list[str]]:
result: dict[str, list[str]] = {}
for item in items:
category = item.category
name = item.name
if category not in result:
result[category] = []
result[category].append(name)
return result
items_group = group_items_by_category(items)
print(items_group)
# {'電子機器': ['ノートPC', 'マウス'], '飲料': ['コーヒー']}
この関数は list[Product] を受け取り、dict[str, list[str]]を返している。型ヒントがあることで、関数の入力と出力が明確になり、使う側も安心してコードを書ける。
型ヒントを使うことで、コードの可読性と保守性が大幅に向上する。特にコレクション型では、要素の型まで指定することで、データ構造が明確になる。Optional型を使えば、Noneの可能性がある値を安全に扱えるようになる。