Difficulty: Advanced
What are metaclasses in Python? When would you use them?
A metaclass is the class of a class. Just as a class defines how instances behave, a metaclass defines how classes behave.
In Python, 'type' is the default metaclass. When you write 'class Foo:', Python calls type('Foo', bases, namespace) to create the class.
Metaclass use cases: - Enforcing class contracts (required methods/attributes) - Automatic registration of subclasses - Modifying class creation (adding methods, changing attributes) - ORM field mapping (Django models, SQLAlchemy) - Singleton pattern
Modern alternatives: __init_subclass__ (Python 3.6+) and class decorators handle most metaclass use cases more simply.
# Everything is an object, and every object has a type
print(type(42)) # <class 'int'>
print(type('hello')) # <class 'str'>
print(type(int)) # <class 'type'>
print(type(type)) # <class 'type'> (type is its own metaclass)
# Classes are instances of type
class MyClass:
x = 10
def greet(self):
return 'hello'
# The above is equivalent to:
MyClass2 = type('MyClass2', (), {'x': 10, 'greet': lambda self: 'hello'})
print(type(MyClass)) # <class 'type'>
print(MyClass.x) # 10
print(MyClass2.x) # 10
# Inheritance
class Child(MyClass):
pass
Child2 = type('Child2', (MyClass,), {})
print(Child2().greet()) # 'hello'
type() is both a function (returns type of object) and a class (the metaclass of all classes). All classes are instances of type.
# Metaclass that enforces required methods
class InterfaceMeta(type):
def __new__(mcs, name, bases, namespace):
cls = super().__new__(mcs, name, bases, namespace)
# Skip check for the base class itself
if bases: # Only check subclasses
required = getattr(cls, '_required_methods', [])
for method in required:
if method not in namespace:
raise TypeError(
f"{name} must implement {method}()"
)
return cls
class Plugin(metaclass=InterfaceMeta):
_required_methods = ['execute', 'cleanup']
# This works:
class GoodPlugin(Plugin):
def execute(self):
return 'executing'
def cleanup(self):
return 'cleaning'
print(GoodPlugin().execute()) # 'executing'
# This raises TypeError at class definition time:
# class BadPlugin(Plugin):
# def execute(self):
# return 'executing'
# # Missing cleanup()!
# TypeError: BadPlugin must implement cleanup()
The metaclass __new__ is called when the CLASS is created (not when instances are created). This allows validating the class definition itself.
# __init_subclass__ (Python 3.6+) - simpler than metaclasses
class Plugin:
_registry = {}
def __init_subclass__(cls, plugin_name=None, kwargs):
super().__init_subclass__(kwargs)
name = plugin_name or cls.__name__.lower()
Plugin._registry[name] = cls
print(f"Registered plugin: {name}")
class JsonPlugin(Plugin, plugin_name='json'):
def process(self):
return 'Processing JSON'
class CsvPlugin(Plugin, plugin_name='csv'):
def process(self):
return 'Processing CSV'
class XmlPlugin(Plugin): # Uses class name as default
def process(self):
return 'Processing XML'
print(Plugin._registry)
# {'json': <class 'JsonPlugin'>, 'csv': <class 'CsvPlugin'>, 'xmlplugin': <class 'XmlPlugin'>}
# Factory pattern using registry
def get_plugin(name):
cls = Plugin._registry.get(name)
if cls:
return cls()
raise ValueError(f"Unknown plugin: {name}")
plugin = get_plugin('json')
print(plugin.process()) # 'Processing JSON'
__init_subclass__ is called every time a class is subclassed. It handles 90% of metaclass use cases (registration, validation) without the complexity.
Metaclasses, type, __new__, __init_subclass__, Class Creation