Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Lernen __subclasshook__ and Custom Membership | ABCs in Depth
Python Abstract Base Classes

__subclasshook__ and Custom Membership

Swipe um das Menü anzuzeigen

register() requires explicit opt-in for each class. __subclasshook__ goes further – it lets an ABC automatically accept any class that satisfies a structural condition, without requiring registration at all. This is how Python's built-in ABCs like Iterable work.

How __subclasshook__ Works

__subclasshook__ is a class method called by isinstance() and issubclass() before consulting the MRO or the registered subclasses. It returns:

  • True – the class is considered a subclass;
  • False – the class is explicitly not a subclass;
  • NotImplemented – fall through to normal lookup.
1234567891011121314151617181920212223
from abc import ABC, abstractmethod # ABC that automatically accepts any class with a serialize() method class Serializable(ABC): @abstractmethod def serialize(self): pass @classmethod def __subclasshook__(cls, subclass): if cls is Serializable: if any("serialize" in klass.__dict__ for klass in subclass.__mro__): return True return NotImplemented # A class that never heard of Serializable class TransactionRecord: def serialize(self): return {"id": "TX-001", "amount": 4500.0} # Passes isinstance() without register() or inheritance print(isinstance(TransactionRecord(), Serializable)) # True print(issubclass(TransactionRecord, Serializable)) # True

How the Standard Library Uses __subclasshook__

collections.abc.Iterable uses exactly this mechanism – any class that defines __iter__ is automatically considered an Iterable:

12345678910111213141516
from collections.abc import Iterable # Custom class with __iter__ – no inheritance from Iterable class DataStream: def __init__(self, records): self._records = records def __iter__(self): return iter(self._records) stream = DataStream([{"id": 1}, {"id": 2}, {"id": 3}]) print(isinstance(stream, Iterable)) # True – __subclasshook__ recognized __iter__ for record in stream: print(record)

Combining __subclasshook__ with Abstract Methods

__subclasshook__ controls isinstance()/issubclass() checks, but does not enforce abstract methods on real subclasses. The two mechanisms are independent:

1234567891011121314151617181920212223242526
from abc import ABC, abstractmethod class Runnable(ABC): @abstractmethod def run(self): pass @classmethod def __subclasshook__(cls, subclass): if cls is Runnable: if any("run" in klass.__dict__ for klass in subclass.__mro__): return True return NotImplemented # Structural check passes – run() is present class BackgroundJob: def run(self): print("Running background job") print(isinstance(BackgroundJob(), Runnable)) # True # Real subclass still gets enforcement class BrokenJob(Runnable): pass # Missing run() job = BrokenJob() # TypeError – abstract method not implemented

register() vs __subclasshook__

question mark

What should __subclasshook__ return to signal that normal ABC membership lookup should proceed?

Wählen Sie die richtige Antwort aus

War alles klar?

Wie können wir es verbessern?

Danke für Ihr Feedback!

Abschnitt 2. Kapitel 4

Fragen Sie AI

expand

Fragen Sie AI

ChatGPT

Fragen Sie alles oder probieren Sie eine der vorgeschlagenen Fragen, um unser Gespräch zu beginnen

Abschnitt 2. Kapitel 4
some-alt