Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Apprendre Virtual Subclasses and register() | ABCs in Depth
Python Abstract Base Classes

Virtual Subclasses and register()

Glissez pour afficher le menu

ABCs can recognize classes as subclasses even when those classes do not inherit from the ABC. This is called virtual subclassing – the class is registered with the ABC and passes isinstance() and issubclass() checks without any inheritance relationship.

The Problem register() Solves

Sometimes you want a class to satisfy an ABC interface without modifying its source code. This is common when integrating third-party classes or built-in types into your own ABC hierarchy:

1234567891011121314
from abc import ABC, abstractmethod class Serializable(ABC): @abstractmethod def serialize(self): pass # A third-party class you cannot modify class ExternalReport: def serialize(self): return {"type": "external", "data": "..."} # Without register() – isinstance fails print(isinstance(ExternalReport(), Serializable)) # False

Using register()

ABC.register(subclass) marks a class as a virtual subclass. It passes isinstance() and issubclass() checks without inheriting:

12345678910111213141516171819
from abc import ABC, abstractmethod class Serializable(ABC): @abstractmethod def serialize(self): pass class ExternalReport: def serialize(self): return {"type": "external", "data": "..."} # Registering the external class as a virtual subclass Serializable.register(ExternalReport) print(isinstance(ExternalReport(), Serializable)) # True print(issubclass(ExternalReport, Serializable)) # True # But it is NOT in the MRO print(Serializable in ExternalReport.__mro__) # False

register() as a Decorator

register() can also be used as a class decorator:

123456789101112131415161718
from abc import ABC, abstractmethod class Cacheable(ABC): @abstractmethod def cache_key(self): pass @Cacheable.register class UserSession: def __init__(self, session_id): self.session_id = session_id def cache_key(self): return f"session:{self.session_id}" session = UserSession("sess-001") print(isinstance(session, Cacheable)) # True print(session.cache_key()) # "session:sess-001"

No Enforcement for Virtual Subclasses

The critical difference between real and virtual subclasses: register() does not enforce abstract method implementation. A virtual subclass that is missing required methods will not raise TypeError on instantiation:

1234567891011121314151617
from abc import ABC, abstractmethod class Exportable(ABC): @abstractmethod def export(self): pass class BrokenExporter: pass # Missing export() Exportable.register(BrokenExporter) # No TypeError – virtual subclasses bypass enforcement broken = BrokenExporter() print(isinstance(broken, Exportable)) # True – but export() is missing! broken.export() # AttributeError at call time

Use register() when you are confident the class satisfies the interface. Prefer real inheritance when you want enforcement.

Real vs Virtual Subclasses

question mark

What is the key difference between a real subclass and a virtual subclass registered with register()?

Sélectionnez la réponse correcte

Tout était clair ?

Comment pouvons-nous l'améliorer ?

Merci pour vos commentaires !

Section 2. Chapitre 3

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 2. Chapitre 3
some-alt