型ヒントと静的解析
基本の型ヒント
# 変数の型ヒント
name: str = "太郎"
age: int = 25
pi: float = 3.14
is_active: bool = True
# 関数の型ヒント
def greet(name: str) -> str:
return f"こんにちは、{name}さん"
def add(a: int, b: int) -> int:
return a + b
コレクションの型ヒント
# Python 3.9+ はビルトイン型を直接使える
names: list[str] = ["太郎", "花子"]
scores: dict[str, int] = {"数学": 85, "英語": 72}
coordinates: tuple[float, float] = (35.68, 139.69)
unique_ids: set[int] = {1, 2, 3}
# ネスト
matrix: list[list[int]] = [[1, 2], [3, 4]]
users: list[dict[str, str]] = [{"name": "太郎"}]
Optional と Union
from typing import Optional
def find_user(user_id: int) -> Optional[dict]:
"""ユーザーが見つからない場合はNoneを返す"""
if user_id == 1:
return {"name": "太郎"}
return None
# Python 3.10+ の新記法
def find_user_new(user_id: int) -> dict | None:
pass
# Union
def process(data: str | bytes | int) -> str:
return str(data)
TypedDict
from typing import TypedDict
class UserDict(TypedDict):
name: str
age: int
email: str
def create_user(data: UserDict) -> None:
print(f"ユーザー作成: {data['name']}")
# 型チェッカーがキーの存在と型を検証
user: UserDict = {"name": "太郎", "age": 25, "email": "taro@example.com"}
Protocol(構造的部分型)
from typing import Protocol
class Drawable(Protocol):
def draw(self) -> None: ...
class Circle:
def draw(self) -> None:
print("円を描画")
class Square:
def draw(self) -> None:
print("四角を描画")
def render(shape: Drawable) -> None:
shape.draw()
render(Circle()) # OK: drawメソッドを持つ
render(Square()) # OK: drawメソッドを持つ
mypy による静的型チェック
# インストール
pip install mypy
# 型チェック実行
mypy my_module.py
mypy --strict my_module.py # 厳格モード
# mypy が検出するエラーの例
def add(a: int, b: int) -> int:
return a + b
result: str = add(1, 2) # error: Incompatible types
まとめ
- 型ヒントはドキュメンテーションとして機能する
Optional[X] は X | None と同義
TypedDict で辞書の構造を定義
Protocol でダックタイピングに型安全性を追加
mypy で型の整合性を自動検証