Virtual Subclasses and register()
メニューを表示するにはスワイプしてください
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:
1234567891011121314from 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:
12345678910111213141516171819from 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:
123456789101112131415161718from 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:
1234567891011121314151617from 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
フィードバックありがとうございます!
AIに質問する
AIに質問する
何でも質問するか、提案された質問の1つを試してチャットを始めてください