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

Showing 11–15 of 15