Sobes.tech
Senior

How do meta-classes work in Python?

sobes.tech AI

Answer from AI

A metaclass in Python is a class that defines the behavior of other classes (just as a regular class defines the behavior of objects). Essentially, a class is an instance of its metaclass. By default, the metaclass for all classes is the type.

The process of creating a class using a metaclass:

  1. Defining the class: class MyClass(BaseClass, metaclass=MyMeta): ... The metaclass is specified using the metaclass argument.
  2. Calling the metaclass: The interpreter sees the metaclass argument and invokes the MyMeta metaclass to create the MyClass class.
  3. Creating the class: The metaclass performs the necessary operations to create the class. This is most often done by overriding the magic methods __new__ or __init__ of the metaclass.

Main methods of a metaclass used for configuring class creation:

# The __new__ method is called first
def __new__(cls, name, bases, dict):
    # name: name of the class being created (string)
    # bases: tuple of parent classes
    # dict: dictionary of class attributes and methods
    # Here, you can modify class attributes, add/remove methods, etc.
    return super().__new__(cls, name, bases, dict)

# The __init__ method is called after __new__,
# if __new__ returns an instance of the metaclass
def __init__(cls, name, bases, dict):
    # cls: the created class
    # name, bases, dict: same arguments as in __new__
    # Here, you can perform additional setup for the created class
    super().__init__(name, bases, dict)

Applications of metaclasses:

  • Automatic registration of classes: A metaclass can register created classes in some registry or list.
  • Adding/modifying attributes and methods: You can automatically add or modify attributes or methods in classes created by this metaclass (e.g., adding decorators, validation).
  • Checking class structure: A metaclass can verify that the defined classes conform to certain rules or patterns.
  • Creating DSL (Domain Specific Language): Metaclasses can help in building domain-specific languages within Python.

Example of a simple metaclass:

class LoggerMeta(type):
    # Override __new__ to add
    # a logging method to all created classes
    def __new__(cls, name, bases, dict):
        # Create a new logging method
        def log_call(self):
            print(f"Method called in class {name}")

        # Add the method to the class attribute dictionary
        # Check to avoid overwriting an existing log_call method
        if 'log_call' not in dict:
             dict['log_call'] = log_call

        # Create the class using the parent metaclass (type)
        return super().__new__(cls, name, bases, dict)

class MyClass(metaclass=LoggerMeta):
    def greet(self):
        print("Hello!")

# Creating an instance
obj = MyClass()

# Calling methods - built-in and added by the metaclass
obj.greet()
obj.log_call()