Metaclasses em Python — são classes especiais que criam e gerenciam outras classes. Como em Python tudo é um objeto, incluindo as classes, as metaclasses podem ser vistas como "classes para classes". Elas fornecem um mecanismo para controlar o processo de criação de classes e modificar seu comportamento no momento da definição.
Como funcionam as metaclasses
Quando o Python encontra uma definição de classe, ele automaticamente usa a metaclasse type para criar essa classe. O processo funciona assim:
class MinhaClasse:
pass
Internamente, o Python executa:
MinhaClasse = type('MinhaClasse', (), {})
Onde:
'MinhaClasse'— nome da classe()— tupla de classes pai{}— dicionário de atributos e métodos da classe
A metaclasse embutida type é responsável por criar todas as classes em Python por padrão.
Criando suas próprias metaclasses
Metaclasses personalizadas são criadas herdando de type e sobrescrevendo seus métodos:
class MinhaMeta(type):
def __new__(cls, name, bases, attrs):
print(f"Criando classe {name}")
attrs['criada_por_metaclasse'] = True
return super().__new__(cls, name, bases, attrs)
class MinhaClasse(metaclass=MinhaMeta):
pass
print(MinhaClasse.criada_por_metaclasse) # True
Métodos principais das metaclasses
__new__
Controla a criação da classe. É chamado antes de __init__ e retorna a nova classe:
class MetaCriacao(type):
def __new__(cls, name, bases, attrs):
# Modificação de atributos antes da criação da classe
attrs['id_classe'] = id(cls)
return super().__new__(cls, name, bases, attrs)
__init__
Inicializa a classe já criada:
class MetaInit(type):
def __init__(cls, name, bases, attrs):
print(f"Inicializando classe {name}")
super().__init__(name, bases, attrs)
__call__
Define o comportamento ao criar instâncias da classe:
class MetaCall(type):
def __call__(cls, *args, **kwargs):
print(f"Criando instância de {cls.__name__}")
return super().__call__(*args, **kwargs)
Exemplos práticos de uso
Conversão automática de atributos
class MetaUpperAttr(type):
def __new__(cls, name, bases, attrs):
uppercase_attrs = {}
for attr_name, attr_value in attrs.items():
if not attr_name.startswith('__'):
uppercase_attrs[attr_name.upper()] = attr_value
else:
uppercase_attrs[attr_name] = attr_value
return super().__new__(cls, name, bases, uppercase_attrs)
class MinhaClasse(metaclass=MetaUpperAttr):
attr1 = 'valor1'
attr2 = 'valor2'
print(hasattr(MinhaClasse, 'ATTR1')) # True
print(hasattr(MinhaClasse, 'attr1')) # False
Implementação do padrão Singleton
class MetaSingleton(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 ConexaoBanco(metaclass=MetaSingleton):
def __init__(self):
print("Criando conexão com o banco de dados")
db1 = ConexaoBanco()
db2 = ConexaoBanco()
print(db1 is db2) # True
Validação da estrutura de classes
class MetaValidacao(type):
def __new__(cls, na