Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Apprendre What typing.Protocol Is and How It Differs | Protocols vs ABCs
Python Abstract Base Classes

What typing.Protocol Is and How It Differs

Glissez pour afficher le menu

Python 3.8 introduced typing.Protocol as a way to express structural typing – defining an interface based on what methods an object has, without requiring inheritance. Where ABCs use nominal typing ("this class is a subclass of X"), Protocols use structural typing ("this class has the right methods").

Nominal vs Structural Typing

Nominal typing (ABCs): a class must explicitly inherit from or register with the ABC to be considered compatible.

Structural typing (Protocols): a class is compatible if it has the required methods, regardless of its inheritance chain.

12345678910111213141516171819202122232425262728293031
from abc import ABC, abstractmethod from typing import Protocol # Nominal: must inherit from Serializable class Serializable(ABC): @abstractmethod def serialize(self): pass # Structural: any class with serialize() qualifies class SerializableProtocol(Protocol): def serialize(self) -> str: ... # A class that has serialize() but does not inherit from anything class TradeRecord: def serialize(self): return '{"id": "TX-001", "amount": 4500.0}' # ABC – fails without inheritance or register() print(isinstance(TradeRecord(), Serializable)) # False # Protocol – passes because the method exists from typing import runtime_checkable @runtime_checkable class SerializableProtocol(Protocol): def serialize(self) -> str: ... print(isinstance(TradeRecord(), SerializableProtocol)) # True

Defining a Protocol

A Protocol class inherits from typing.Protocol. Methods are defined with ... (ellipsis) as the body – they describe the interface, not an implementation:

123456789101112131415161718192021222324252627282930313233
from typing import Protocol # Protocol defining the interface for a data exporter class Exporter(Protocol): def export(self, data: list) -> str: ... def get_format(self) -> str: ... # Any class with these methods satisfies the protocol class CsvExporter: def export(self, data): return ",".join(str(item) for item in data) def get_format(self): return "CSV" class JsonExporter: def export(self, data): import json return json.dumps(data) def get_format(self): return "JSON" # Both satisfy the protocol without inheriting from it def run_export(exporter: Exporter, data: list) -> None: print(f"Format: {exporter.get_format()}") print(exporter.export(data)) run_export(CsvExporter(), ["TX-001", "TX-002"]) run_export(JsonExporter(), ["TX-001", "TX-002"])

@runtime_checkable

By default, Protocol membership cannot be checked at runtime with isinstance(). Decorating with @runtime_checkable enables it – but the check only verifies method presence, not signatures:

12345678910111213141516
from typing import Protocol, runtime_checkable @runtime_checkable class Runnable(Protocol): def run(self) -> None: ... class BackgroundJob: def run(self): print("Running background job") class BrokenJob: pass print(isinstance(BackgroundJob(), Runnable)) # True – has run() print(isinstance(BrokenJob(), Runnable)) # False – missing run()

ABCs vs Protocols at a Glance

question mark

What is the key difference between nominal typing (ABCs) and structural typing (Protocols)?

Sélectionnez la réponse correcte

Tout était clair ?

Comment pouvons-nous l'améliorer ?

Merci pour vos commentaires !

Section 3. Chapitre 1

Demandez à l'IA

expand

Demandez à l'IA

ChatGPT

Posez n'importe quelle question ou essayez l'une des questions suggérées pour commencer notre discussion

Section 3. Chapitre 1
some-alt