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

__subclasshook__ and Custom Membership

Svep för att visa menyn

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?

Vänligen välj det korrekta svaret

Var allt tydligt?

Hur kan vi förbättra det?

Tack för dina kommentarer!

Avsnitt 2. Kapitel 4

Fråga AI

expand

Fråga AI

ChatGPT

Fråga vad du vill eller prova någon av de föreslagna frågorna för att starta vårt samtal

Avsnitt 2. Kapitel 4
some-alt