Protocolと抽象基底クラス:レビュー視点での使い分け基準
はじめに
Pythonの型定義において、ProtocolとABC(抽象基底クラス)はともに「インターフェース設計」を担う強力な構文です。
しかし、コードレビューの現場ではしばしばこの2つが無思慮に混用されており、設計意図が不透明なまま進行するケースが後を絶ちません。
本記事では、レビューアー視点で「ProtocolとABCのどちらを採用すべきか」を判断するための明確な基準を提示します。
実務コードに現れる具体構造をベースに、違いを理解し、設計上の選択とそのレビュー観点を整理していきます。
使用目的から設計意図を読み解く
typing.Protocolは構造的部分型(structural subtyping)を実現するための仕組みであり、「この属性やメソッドを持っていれば実装されたと見なす」性質を持ちます。
JavaやC++のinterfaceとは異なり、明示的な継承を必要とせず、「形が合えば使える」ことが最大の特徴です。
abc.ABCを基底としたクラス設計は、「明示的に継承されたクラスのみが、その抽象クラスを満たしている」と見なされます。
設計上の契約を強制し、サブクラスに明示的な実装を求めるため、実装保証を重視する設計に向いています。
レビュー時に最も注視すべきは、「設計意図と構文選択の整合性」です。
意図が「どのような機能を提供するか」ではなく、「誰がどう使うか」になっている場合、Protocolの方が設計として適しているケースが多く見られます。
典型コードとレビュー指摘例
from abc import ABC, abstractmethod
class Notifier(ABC):
@abstractmethod
def send(self, message: str) -> None:
pass
class PrintNotifier:
def send(self, message: str) -> None:
print(message)
def notify_all(n: Notifier, message: str):
n.send(message)
# 実行時エラーになる
notify_all(PrintNotifier(), "Hello")@Reviewer: `PrintNotifier`は構造的には`send()`を持っており、Protocolでの定義であれば利用可能です。
「型チェック強制」よりも「柔軟な実装の受容」が意図される場合、ABCよりProtocolが設計意図に沿います。- インターフェースを後付けで柔軟に適用したい(Duck Typingの形式保証)
- 複数のクラスに似た形の振る舞いが自然発生的に存在する
- ライブラリ使用者に特定の継承を強制せず、振る舞い契約のみを共有したい
- 派生クラスに実装の義務を強く求める(契約的強制)
- 既存クラスとは異なる階層構造を作りたい
- 単体テストなどで
isinstance()による型判定が必要になる
使用意図の視覚化:クラス設計図
図中のように、設計上の「用途拡張性」と「明示的な継承の契約」を分けて扱う構図を可視化することで、レビュー判断の軸が整理されます。
実務レビューにおける指摘テンプレート
@Reviewer: このインターフェースは外部ライブラリ由来のクラスにも使われる構造です。
特定の継承を強制しないためにも`Protocol`ベースに切り替える方が柔軟性・再利用性が向上します。@Reviewer: 抽象クラスとして共通初期化処理も含まれており、継承構造を意図的に作る場合は`ABC`を明示したほうがコードの意図が明確になります。補足:動的型チェックと静的型チェック
Protocolはmypyやpyrightなどの静的型チェックでのみ機能する構造です。- 実行時の型判定では
isinstance(obj, MyProtocol)は使用できません(@runtime_checkableで一部緩和可能)。 ABCは実行時の型チェックにも対応するため、テスト時に動的判定を重視する場合は有効です。
Protocolに@runtime_checkableを付与することで、isinstance()やissubclass()が実行時に使えるようになります。
ただし、これはProtocolの柔軟性をある程度犠牲にする行為でもあります。
結論:レビュー観点としての判断軸
| 観点 | Protocol | 抽象基底クラス(ABC) |
|---|---|---|
| 継承の強制性 | 不要 | 必要 |
| 静的型チェック | 対応(mypy/pyright等) | 対応 |
| 実行時チェック | 基本非対応(※装飾で一部可能) | 対応 |
| 拡張性・後付け設計 | 高い | 低い |
| 明示的契約の強制 | 不可 | 可能 |
| 利用者の自由度 | 高い | 制限される |
レビューアーは、「誰が使うか」「どう拡張されるか」の視点を軸に、この2つを明確に選び分ける必要があります。
型設計は型安全性そのものではなく、「設計意図を形式的にどう表現するか」の一手段です。
構文の選択が設計方針を誤認させるようであれば、それはレビューによって修正されるべきポイントです。
