🧬

How to Use Metaclasses in Python

PythonAdvanced

Control class creation with metaclasses.

Code Example

Python
# Metaclass that adds methods
class MethodAdder(type):
    def __new__(mcs, name, bases, namespace):
        # Add a method to the class
        namespace['greet'] = lambda self: f"Hello from {name}!"
        return super().__new__(mcs, name, bases, namespace)

class MyClass(metaclass=MethodAdder):
    pass

obj = MyClass()
print(obj.greet())

# Metaclass that validates attributes
class Validator(type):
    def __new__(mcs, name, bases, namespace):
        # Check for required attributes
        if 'required_attr' not in namespace:
            raise TypeError(f"{name} must define 'required_attr'")
        return super().__new__(mcs, name, bases, namespace)

# This works
class ValidClass(metaclass=Validator):
    required_attr = "I'm required"

print(f"\nValidClass created: {ValidClass.required_attr}")

# This fails
try:
    class InvalidClass(metaclass=Validator):
        pass
except TypeError as e:
    print(f"Error: {e}")

# Singleton metaclass
class Singleton(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 Database(metaclass=Singleton):
    def __init__(self):
        self.connection = "Connected"

db1 = Database()
db2 = Database()
print(f"\nSame instance: {db1 is db2}")

# Attribute access control
class UpperCaseMeta(type):
    def __new__(mcs, name, bases, namespace):
        # Convert all method names to uppercase
        new_namespace = {}
        for key, value in namespace.items():
            if callable(value) and not key.startswith('__'):
                new_namespace[key.upper()] = value
            else:
                new_namespace[key] = value
        return super().__new__(mcs, name, bases, new_namespace)

class MyClass(metaclass=UpperCaseMeta):
    def my_method(self):
        return "Hello"

obj = MyClass()
print(f"\nMethod: {obj.MY_METHOD()}")

Explanation

Metaclasses control class creation. Inherit from type. Override __new__ to modify class. Use for validation, singleton pattern, auto-generation.

Related Tutorials