AAtsushi's Blog

【Python】PEP 544のProtocolについて

この記事はAIで書いています。

【Python】PEP 544(Protocol)を初心者向けに分かりやすく解説!ダックタイピングを型ヒントでも実現する仕組み

Pythonの型ヒントを勉強していると、「PEP 544」 や「Protocol(プロトコル)」 という言葉を見かけることがありませんか?

一言でいうと、PEP 544は「Python本来の『ダックタイピング』の柔軟性を、静的型チェックでも安全に使えるようにした仕組み」 です。

この記事では、PEP 544が導入された背景と、具体的な使い方を分かりやすく解説します。


1. そもそも「ダックタイピング」とは?

Pythonには、昔からダックタイピング(Duck Typing) という文化があります。

「アヒル(Duck)のように歩き、アヒルのように鳴くなら、それはアヒルだ」

つまり、オブジェクトの「実際のクラス(名前)」が何であるかは重要ではなく、「必要なメソッドや属性を持っているか(何ができるか)」 を重視する考え方です。


2. これまでの型ヒントの問題点

しかし、Python 3.5で導入された「型ヒント(Type Hints)」は、基本的に「名目的部分型(Nominal Subtyping)」 でした。 これは、クラスの「名前(継承関係)」をベースに型をチェックする仕組みです。

例えば、以下のコードを見てみましょう。

class Dog:
    def speak(self) -> None:
        print("Woof!")

# Dog型(またはDogを継承したクラス)しか受け付けない
def make_it_speak(animal: Dog):
    animal.speak()

このとき、まったく同じ speak() メソッドを持つ Cat クラスを作ったとします。

class Cat:
    def speak(self) -> None:
        print("Meow!")

cat = Cat()
make_it_speak(cat)  # 実行はできるが、型チェック(mypyなど)でエラーになる!

Pythonの実行環境としては問題なく動きます(ダックタイピング)。 しかし、型チェックツール(mypyやPyrightなど)からは「Dog型が必要なのにCat型が渡されている」 と怒られてしまいます。

これを解決するためにわざわざ共通の親クラスを作って継承させるのは、Pythonの柔軟性を損なってしまい不便でした。


3. PEP 544の解決策:「構造的部分型」と Protocol

この問題を解決するために、PEP 544で導入されたのが「構造的部分型(Structural Subtyping)」 です。 クラスの名前ではなく、クラスの「構造(持っているメソッド)」で型を判断します。

これを実現するために使うのが、typing.Protocol です。

具体的なコード例

from typing import Protocol

# 1. 「speakメソッドを持っている」というルール(プロトコル)を定義
class Speaker(Protocol):
    def speak(self) -> None:
        ...  # 中身は省略(パス)する

# 2. 普通にクラスを作る(明示的な継承は不要!)
class Dog:
    def speak(self) -> None:
        print("Woof!")

class Cat:
    def speak(self) -> None:
        print("Meow!")

# 3. 引数の型に「Protocol」を指定する
def make_it_speak(animal: Speaker):
    animal.speak()

# どちらを渡しても、型チェックを無事に通過する!
make_it_speak(Dog())
make_it_speak(Cat())

何が起きているの?

  • Speaker という「ルール(インターフェース)」を定義しました。
  • DogCat も、Speaker継承していません
  • しかし、どちらも speak() メソッドを持っているので、自動的に Speaker 型の一種として認められます。

4. PEP 544(Protocol)を使うメリット

  1. 明示的な継承(インポート)が不要 他人が作ったライブラリや標準ライブラリのクラスであっても、必要なメソッドさえ揃っていれば型チェックを通せます。
  2. コードの結合度が下がる 「このクラスに依存する」のではなく「この機能(メソッド)を持つオブジェクトに依存する」という設計ができるため、コードがスッキリします。
  3. 安全性と柔軟性の両立 Pythonらしい自由で柔軟なダックタイピングの良さを残しつつ、静的型チェックの恩恵(バグの早期発見、エディタ補完)を最大限に受けられます。

まとめ

  • PEP 544 は、Pythonに Protocol を導入した仕様。
  • クラスの継承関係ではなく、持っているメソッド(構造)で型をチェックする 仕組み。
  • Python本来の「ダックタイピング」を型ヒントの世界で安全に実現できる 神機能。

モダンなPython開発(特に大規模開発や堅牢なライブラリ開発)では必須の知識なので、ぜひ活用してみてください!