Enforcing Design Patterns
One common use case for metaclass inheritance is to enforce design patterns across an inheritance hierarchy. For example, you can use a metaclass to ensure that all classes in the hierarchy follow the Singleton pattern, where only one instance of the class can exist.
class Singleton(type):
_instances = {}
def __call__(cls, *args, **kwargs):
if cls not in cls._instances:
cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs)
return cls._instances[cls]
class MyClass(metaclass=Singleton):
pass
obj1 = MyClass()
obj2 = MyClass()
print(obj1 is obj2) ## True
In this example, the Singleton
metaclass ensures that only one instance of MyClass
can be created, regardless of how many times the class is instantiated.
Automatic Attribute Management
Metaclass inheritance can also be used to automatically manage the attributes of a class. For example, you can use a metaclass to automatically add or remove attributes based on certain conditions.
class AutoAttrMeta(type):
def __new__(cls, name, bases, attrs):
if name.startswith("Auto"):
attrs["auto_attr"] = f"This is an automatically added attribute for {name}"
return super().__new__(cls, name, bases, attrs)
class AutoClass(metaclass=AutoAttrMeta):
pass
class ManualClass:
pass
print(AutoClass.auto_attr) ## "This is an automatically added attribute for AutoClass"
print(hasattr(ManualClass, "auto_attr")) ## False
In this example, the AutoAttrMeta
metaclass automatically adds an auto_attr
attribute to any class whose name starts with "Auto".
Domain-Specific Language (DSL) Creation
Metaclass inheritance can be used to create domain-specific languages (DSLs) in Python. By defining a metaclass that customizes the class creation process, you can create a DSL that allows users to express domain-specific concepts using Python syntax.
class QueryMeta(type):
def __new__(cls, name, bases, attrs):
if name != "Query":
attrs["_query"] = attrs.get("_query", []) + [name.lower()]
return super().__new__(cls, name, bases, attrs)
class Query(metaclass=QueryMeta):
pass
class Select(Query):
pass
class From(Query):
pass
class Where(Query):
pass
query = Select() + From("users") + Where("name = 'John'")
print(query._query) ## ['select', 'from', 'where']
In this example, the QueryMeta
metaclass is used to create a simple DSL for building SQL-like queries.