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:
- Defining the class:
class MyClass(BaseClass, metaclass=MyMeta): ...The metaclass is specified using themetaclassargument. - Calling the metaclass: The interpreter sees the
metaclassargument and invokes theMyMetametaclass to create theMyClassclass. - 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()