Advanced Topics
Metaprogramming
Code that generates or manipulates code at runtime
Interview: Advanced Python — frequently probed in senior roles
Metaprogramming is the technique of writing code that inspects, generates, or modifies other code at runtime. Python provides two primary mechanisms: decorators (function/class wrappers) and metaclasses (classes that create classes).
Decorators Recap
Decorators are the most common form of metaprogramming. They wrap a function or class to extend its behavior without modifying the original source code.
A decorator is simply a callable that takes a function and returns a new function. The @decorator syntax is sugar for func = decorator(func).
Metaclasses
A metaclass is the "class of a class." Just as an object is an instance of a class, a class is an instance of a metaclass. The default metaclass is type.
When you write class Foo: pass, Python internally calls type('Foo', (), {}) to create the class object. By supplying a custom metaclass, you intercept this creation step.
When to Use Metaclasses
Most applications never need metaclasses. Prefer __init_subclass__ (Python 3.6+) or class decorators for simpler use cases. Metaclasses shine in framework development (ORMs, serialization libraries) where you need to enforce rules across an entire class hierarchy.
The Descriptor Protocol
Descriptors are objects that define __get__, __set__, and/or __delete__. They power Python's attribute access mechanism and are the foundation of @property, @classmethod, and @staticmethod.
Common Pitfalls
- Over-engineering: Don't use a metaclass when a decorator or
__init_subclass__suffices. - Multiple metaclass conflicts: If class A has metaclass MA and class B has metaclass MB, a class inheriting both will raise
TypeError. - Debugging difficulty: Metaclass logic runs at class creation time, making stack traces confusing.
Use Cases
Plugin/Extension frameworks with auto-registration
ORM model field definitions (Django, SQLAlchemy)
API validation and serialization libraries
Enforcing coding standards across a class hierarchy
Common Mistakes
Using metaclasses when __init_subclass__ or class decorators suffice
Forgetting functools.wraps on decorators — breaks introspection and debugging
Multiple metaclass inheritance causing TypeError conflicts
Not understanding the MRO (Method Resolution Order) when combining metaclasses