Python の TypeVar とジェネリクス

TypeVar を使うと、ジェネリックな関数や型を定義できます。入力と出力の型の関係を保ちながら、さまざまな型に対応する関数を作れます。

基本的な使い方

TypeVar で型変数を定義し、関数の引数と戻り値で同じ型を表現します。

from typing import TypeVar

T = TypeVar("T")

def identity(x: T) -> T:
    return x

result1 = identity(42)       # int を受け取り int を返す
result2 = identity("hello")  # str を受け取り str を返す

型チェッカーは、引数の型から戻り値の型を推論します。

型の制約

bound を指定すると、その型またはサブクラスに制限できます。

from typing import TypeVar

class Animal:
    def speak(self) -> str:
        return "..."

class Dog(Animal):
    def speak(self) -> str:
        return "Woof!"

T = TypeVar("T", bound=Animal)

def make_speak(animal: T) -> T:
    print(animal.speak())
    return animal

特定の型のみ許可

複数の型を列挙して制限することもできます。

from typing import TypeVar

T = TypeVar("T", int, float)

def double(x: T) -> T:
    return x * 2  # type: ignore

double(5)    # OK
double(3.14) # OK
double("a")  # 型エラー

リストのジェネリクス

コンテナ型と組み合わせると、要素の型を保持できます。

from typing import TypeVar, List

T = TypeVar("T")

def first(items: List[T]) -> T:
    return items[0]

x = first([1, 2, 3])      # int
y = first(["a", "b"])     # str

TypeVar を活用すると、汎用的でありながら型安全なコードを書けます。