Metaclasses & Class Customization
15 questions found
How can a metaclass be used to implement the Singleton design pattern more robustly than overriding __new__ alone?
Advanced
A Singleton metaclass overrides __call__(cls, *args, **kwargs) (the method invoked when you 'call' the class to create an instance) to check a per-class instance cache and return the existing instance instead of creating a new one. This centralizes the singleton logic in one reusable metaclass applicable to any class, rather than duplicating __new__ overrides in every singleton class.
class SingletonMeta(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super().__call__(*args, **kwargs)
return cls._instances[cls]
class Config(metaclass=SingletonMeta):
pass
print(Config() is Config()) # True
Real-world example
An application-wide logging configuration class uses a SingletonMeta metaclass so every part of the codebase that instantiates Config() transparently receives the same shared instance.
Common follow-ups: Why is __call__ on the metaclass the right hook, not __new__ on the class?;What are the downsides of singletons for testability?
Multiple Inheritance & MRO;Descriptors & Properties
What is the practical difference between isinstance(obj, cls) and type(obj) is cls, particularly regarding metaclasses and inheritance?
Intermediate
isinstance() respects the full inheritance hierarchy (and can be customized via __instancecheck__ on a metaclass, as ABCs do for virtual subclassing), returning True for subclass instances too. `type(obj) is cls` only matches the exact type, ignoring subclasses entirely -- so it's stricter and generally discouraged unless you specifically need to exclude subclass instances.
class Animal: pass
class Dog(Animal): pass
d = Dog()
print(isinstance(d, Animal)) # True -- respects inheritance
print(type(d) is Animal) # False -- exact type only
Real-world example
A serialization framework uses isinstance() checks against ABCs (like collections.abc.Mapping) so it correctly handles any dict-like object, including custom subclasses, rather than only exact dict instances.
Common follow-ups: How does __instancecheck__ let ABCs support virtual subclasses?;When is the exact-type check actually the right choice?
Multiple Inheritance & MRO;Data Types & Structures
How does __instancecheck__ and __subclasscheck__ on a metaclass enable 'virtual subclassing' as used by collections.abc?
Advanced
ABCMeta overrides __instancecheck__ and __subclasscheck__ so that `isinstance(obj, SomeABC)` can return True even if the object's class never explicitly inherited from SomeABC, as long as it was registered via `SomeABC.register(OtherClass)` or structurally satisfies the ABC's requirements. This lets unrelated classes (like built-in list) be recognized as implementing collections.abc.Sequence without modifying their actual inheritance chain.
from collections.abc import Sequence
print(isinstance([1,2,3], Sequence)) # True -- list wasn't explicitly declared as Sequence subclass
class MyIterable:
pass
Sequence.register(MyIterable)
print(isinstance(MyIterable(), Sequence)) # True via virtual registration
Real-world example
A validation framework checks `isinstance(value, collections.abc.Mapping)` to accept both built-in dicts and custom dict-like classes from third-party libraries that were registered as virtual subclasses.
Common follow-ups: What's the performance cost of custom __instancecheck__ implementations?;How does register() differ from actual inheritance?
Multiple Inheritance & MRO;Magic Methods & Operator Overloading
Why do most Python developers rarely need to write a custom metaclass in everyday code?
Beginner
Metaclasses solve problems at the class-creation level, but most common needs -- validation, registration, adding methods, enforcing interfaces -- are better and more simply solved with class decorators, __init_subclass__, descriptors, or plain inheritance. Metaclasses add real complexity and can conflict with other metaclasses, so the Python community favors reaching for them only when these simpler tools genuinely can't express the requirement.
# Simpler alternative to a metaclass for registration:
class Plugin:
registry = []
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
cls.registry.append(cls)
Real-world example
A code reviewer suggests replacing a newly-introduced custom metaclass with __init_subclass__ since the team's actual need (auto-registering subclasses) doesn't require full metaclass power.
Common follow-ups: What's the famous Tim Peters quote about metaclasses?;What are legitimate cases that still require a metaclass?
Multiple Inheritance & MRO;Decorators
What is the __mro__ attribute and how does it relate to metaclasses?
Beginner
__mro__ is a tuple on every class showing its Method Resolution Order -- the linear sequence Python searches through when looking up an attribute or method, computed by the C3 linearization algorithm. Since ordinary classes are instances of the `type` metaclass, __mro__ itself is exposed as a class attribute accessible via ClassName.__mro__ or the equivalent ClassName.mro() method.
class A: pass
class B(A): pass
class C(A): pass
class D(B, C): pass
print(D.__mro__)
# (<class D>, <class B>, <class C>, <class A>, <class object>)
Real-world example
Debugging a diamond-inheritance bug, a developer prints D.__mro__ to see the exact order Python will search for a method, revealing why C's override of a method is being used instead of B's.
Common follow-ups: How does C3 linearization differ from simple depth-first search?;Can __mro__ be customized via a metaclass?
Multiple Inheritance & MRO;Metaclasses & Class Customization