Python の Self 型と再帰的な型定義
Self 型は Python 3.11 で導入され、メソッドが自身のクラス型を返すことを正確に表現できます。継承時にも正しい型が推論されます。
問題の背景
従来、自身を返すメソッドの型付けは面倒でした。
from typing import TypeVar
T = TypeVar("T", bound="Builder")
class Builder:
def set_name(self: T, name: str) -> T:
self.name = name
return self
クラスごとに TypeVar を定義する必要がありました。
Self 型の基本
from typing import Self
class Builder:
def set_name(self, name: str) -> Self:
self.name = name
return self
def set_value(self, value: int) -> Self:
self.value = value
return self
Self は「このメソッドを呼び出したインスタンスの型」を意味します。
継承での動作
from typing import Self
class Animal:
def set_name(self, name: str) -> Self:
self.name = name
return self
class Dog(Animal):
def set_breed(self, breed: str) -> Self:
self.breed = breed
return self
dog = Dog().set_name("Buddy").set_breed("Labrador")
# dog の型は Dog
Animal.set_name の返り値は Dog として推論されます。TypeVar を使った場合と同じ効果ですが、より簡潔です。
ファクトリメソッド
from typing import Self
class Config:
def __init__(self, data: dict):
self.data = data
@classmethod
def from_file(cls, path: str) -> Self:
with open(path) as f:
return cls(json.load(f))
class AppConfig(Config):
pass
config = AppConfig.from_file("config.json")
# config の型は AppConfig
再帰的な型定義
from typing import Self
class Node:
def __init__(self, value: int):
self.value = value
self.children: list[Self] = []
def add_child(self, child: Self) -> Self:
self.children.append(child)
return self
Self 型により、メソッドチェーンやファクトリパターンの型付けが簡潔かつ正確になります。