Protocol を使うと、ダックタイピングに型ヒントを付けられます。特定のメソッドやプロパティを持つオブジェクトを受け入れる関数を、型安全に定義できます。
基本的な使い方
Protocol クラスを継承して、必要なメソッドを定義します。
from typing import Protocol class Speakable(Protocol): def speak(self) -> str: ... def make_speak(obj: Speakable) -> None: print(obj.speak())
Protocol を明示的に継承していなくても、speak メソッドを持っていれば型チェックを通過します。
class Dog: def speak(self) -> str: return "Woof!" class Cat: def speak(self) -> str: return "Meow!" make_speak(Dog()) # OK make_speak(Cat()) # OK
複数のメソッドを要求
Protocol に複数のメソッドを定義できます。
from typing import Protocol class Serializable(Protocol): def to_json(self) -> str: ... def from_json(self, data: str) -> None: ...
プロパティの定義
プロパティも Protocol で定義できます。
from typing import Protocol class Named(Protocol): @property def name(self) -> str: ... def greet(obj: Named) -> None: print(f"Hello, {obj.name}!")
抽象基底クラスとの違い
Protocol
継承不要。メソッドの存在だけで適合判定。構造的部分型(structural subtyping)。
ABC(抽象基底クラス)
明示的な継承が必要。名前的部分型(nominal subtyping)。
Protocol は既存のクラスを変更せずに型制約を追加できるため、サードパーティのライブラリとの連携や、柔軟な設計に向いています。