Callable — 関数の型ヒント
Python では関数もオブジェクトであり、変数に代入したり他の関数に渡したりできる。こうした「関数を値として扱う」場面で型ヒントを付けるには Callable を使う。引数の型と戻り値の型を明示することで、コールバックやデコレータのシグネチャを正確に表現できるようになる。
Callable の基本構文
Callable は collections.abc モジュールからインポートして使う。
from collections.abc import Callable
def apply(func: Callable[[int, int], int], a: int, b: int) -> int:
return func(a, b)
def add(x: int, y: int) -> int:
return x + y
result = apply(add, 3, 5) # 8Callable[[int, int], int] は「int を 2 つ受け取り、int を返す関数」を意味する。最初のリストが引数の型、リストの外が戻り値の型だ。
Python 3.8 以前では typing.Callable を使う必要があったが、3.9 以降は collections.abc.Callable が推奨されている。古いコードでは from typing import Callable と書かれていることも多いが、collections.abc.Callableのほうが現在の標準である。
typing.Callable は将来的に非推奨となる可能性がある。
引数なしの関数
引数を取らない関数は、空のリストで表現する。
from collections.abc import Callable
def run_task(task: Callable[[], str]) -> str:
return task()
def greeting() -> str:
return "Hello!"
print(run_task(greeting)) # Hello!Callable[[], str] が「引数なしで str を返す関数」を意味する。リストの中身が空であることに注意しよう。
戻り値が None の関数
副作用だけを持つ関数には、戻り値に None を指定する。
from collections.abc import Callable
def on_click(handler: Callable[[str], None]) -> None:
handler("button_1")
def log_click(element_id: str) -> None:
print(f"Clicked: {element_id}")
on_click(log_click)イベントハンドラやログ関数のように「何かを実行するが値は返さない」パターンでよく使う形だ。
実用例:ソート関数のキー
標準ライブラリの sorted が受け取る key 引数も Callable で型を付けられる。
from collections.abc import Callable
def sort_by(items: list[str], key: Callable[[str], int]) -> list[str]:
return sorted(items, key=key)
words = ["banana", "apple", "fig"]
result = sort_by(words, key=len) # ["fig", "apple", "banana"]key: Callable[[str], int] は「文字列を受け取って整数を返す関数」だ。len はまさにこのシグネチャに合致するので、そのまま渡せる。
高階関数とデコレータ
関数を返す関数にも Callable は使える。デコレータを型付けする典型的なパターンを見てみよう。
from collections.abc import Callable
from functools import wraps
import time
def timer(func: Callable[..., float]) -> Callable[..., float]:
@wraps(func)
def wrapper(*args: object, **kwargs: object) -> float:
start = time.time()
result = func(*args, **kwargs)
print(f"{func.__name__}: {time.time() - start:.3f}s")
return result
return wrapper
@timer
def compute(n: int) -> float:
return sum(range(n)) * 1.0Callable[..., float] の ...(Ellipsis)は「任意の引数を受け取る」ことを示す。引数の型を厳密に指定できない場合に使う記法で、デコレータのように汎用的な関数を包むときに便利だ。
Callable[[int, str], bool] — 引数の型と個数が固定の場合。型チェックが厳密に効く。
Callable[..., bool] — 引数の型を問わない場合。柔軟だが型チェックは緩くなる。
ParamSpec でデコレータを正確に型付けする
Callable[..., T] は便利だが、元の関数のシグネチャが失われてしまう。Python 3.10 で導入された ParamSpec を使えば、引数の型情報を保持したままデコレータを定義できる。
from collections.abc import Callable
from typing import ParamSpec, TypeVar
from functools import wraps
P = ParamSpec("P")
T = TypeVar("T")
def retry(func: Callable[P, T]) -> Callable[P, T]:
@wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> T:
for _ in range(3):
try:
return func(*args, **kwargs)
except Exception:
continue
raise RuntimeError("retries exhausted")
return wrapper
@retry
def fetch(url: str, timeout: int = 30) -> str:
...ParamSpec("P") が元の関数の引数情報をまるごと保持する。これにより、デコレータを通しても fetch の引数の型ヒントが正しく維持される。mypy や IDE の補完もきちんと動く。
TypeAlias と組み合わせる
Callable の型が長くなる場合は、前の記事で紹介した TypeAlias と組み合わせると読みやすくなる。
from collections.abc import Callable
from typing import TypeAlias
EventHandler: TypeAlias = Callable[[str, dict[str, object]], None]
Middleware: TypeAlias = Callable[[dict[str, object]], dict[str, object]]
def register_handler(event: str, handler: EventHandler) -> None:
...
def add_middleware(mw: Middleware) -> None:
...引数の型リストと戻り値の型で関数のシグネチャを記述する。コールバックや高階関数に不可欠。
デコレータなど、関数を包む関数で元のシグネチャを維持したいときに使う。Python 3.10 以降で利用可能。
関数を値として受け渡す場面は、イベント処理、プラグインシステム、テストのモック、非同期タスクの登録など多岐にわたる。Callable で型を明示しておけば、渡す関数のシグネチャが合っているかを実行前に検証でき、バグの早期発見につながる。












