Módulo 11 - Metaclasses e descritores
O que é uma metaclass
10 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026
O que você vai aprender
- Definir metaclass como uma subclasse de type.
- Escrever uma metaclass com __new__ e __init__ que intercepta a criação da classe.
- Usar o argumento metaclass= na declaração da classe.
- Reconhecer os poucos casos em que uma metaclass se justifica.
Ouvir o resumo desta aula
Um recap de cerca de 2 minutos na voz do Valim, para ouvir no trânsito ou na academia.
Ler a transcrição do resumo
Resumo da aula: O que é uma metaclass.
Os objetivos desta aula. Definir metaclass como uma subclasse de type. Escrever uma metaclass com __new__ e __init__ que intercepta a criação da classe. Usar o argumento metaclass= na declaração da classe. Reconhecer os poucos casos em que uma metaclass se justifica.
Veja o essencial, parte por parte.
Uma classe que cria classes. Uma metaclass é uma subclasse de type: uma fábrica de classes personalizada.
__new__ e __init__ da metaclass. Uma metaclass tem dois pontos de entrada, e vale separar o papel de cada um.
Quando (raramente) usar. Se você está em dúvida se precisa de uma metaclass, você não precisa.
Esse foi o resumo do essencial. Para se aprofundar, leia a aula completa e responda os exercícios.
Uma classe que cria classes
Na aula anterior você viu que type fabrica todas as classes. Uma metaclass é apenas uma type sua, personalizada. Como a metaclass é a fábrica, ela é chamada no exato momento em que uma classe é criada, e não quando um objeto dessa classe é instanciado. Essa é a distinção que confunde no começo: uma classe comum controla o nascimento dos objetos; uma metaclass controla o nascimento das classes. É um andar acima.
class MinhaMeta(type):
def __new__(mcs, nome, bases, namespace):
print(f"criando a classe {nome}")
return super().__new__(mcs, nome, bases, namespace)
class Produto(metaclass=MinhaMeta):
preco = 10
# Saida na hora de definir a classe: criando a classe Produto
p = Produto() # aqui nao imprime nada: a metaclass ja rodou antesA metaclass roda quando Produto é definida, não quando um Produto é instanciado.
Repare que a mensagem aparece assim que a classe Produto é declarada, e não quando p = Produto() é executado. Isso comprova o ponto: a metaclass age na criação da classe. Os parâmetros de __new__ são reveladores: nome é o texto do nome da classe, bases é a tupla de classes-mãe e namespace é o dicionário com tudo que foi escrito no corpo da classe, incluindo métodos e atributos como preco. É esse dicionário que você pode inspecionar ou alterar antes de a classe existir de fato.
__new__ e __init__ da metaclass
Uma metaclass tem dois pontos de entrada, e vale separar o papel de cada um. O __new__ cria o objeto-classe e é onde você inspeciona ou modifica o namespace antes de a classe passar a existir. O __init__ recebe a classe já criada e serve para ajustes finais ou registros. Uma metáfora simples: __new__ é a linha de montagem que fabrica a classe; __init__ é a inspeção de qualidade que acontece com a classe pronta na mão.
class RegistroMeta(type):
registro = {}
def __init__(cls, nome, bases, namespace):
super().__init__(nome, bases, namespace)
# A classe ja existe aqui; guardamos numa tabela central.
if bases: # ignora a propria base abstrata
RegistroMeta.registro[nome] = cls
class Base(metaclass=RegistroMeta):
pass
class Boleto(Base):
pass
class Pix(Base):
pass
print(list(RegistroMeta.registro)) # ['Boleto', 'Pix']Um caso real: registrar automaticamente toda subclasse numa tabela central.
Este exemplo é um dos usos legítimos de metaclass: um registro automático. Toda vez que alguém cria uma subclasse de Base, a metaclass a guarda numa tabela, sem que o autor da subclasse precise lembrar de registrar. Frameworks de plugins e serializadores usam essa técnica. Ainda assim, guarde a ressalva: como você verá na última aula do módulo, o gancho __init_subclass__ resolve muitos desses casos de forma mais simples, sem escrever uma metaclass.
Quando (raramente) usar
Essa frase, sobre não precisar de metaclass quando se está em dúvida, é um conselho clássico da comunidade Python e vale levar a sério. Metaclasses são poderosas porque interceptam a criação de toda uma família de classes, mas esse mesmo poder torna o código difícil de entender para quem chega depois. Os casos que de fato pedem metaclass são de biblioteca: ORMs que transformam atributos de classe em colunas de banco, sistemas que impõem uma interface a todas as subclasses, ferramentas que precisam do controle mais profundo possível.
Para código de aplicação, quase sempre há um caminho mais leve. Precisa reagir quando uma classe é criada como filha de outra? __init_subclass__ resolve. Precisa modificar uma classe depois de pronta? Um decorador de classe basta e é mais legível. Precisa controlar o acesso a um atributo? Um descritor, tema da próxima aula, é a ferramenta certa. Reserve a metaclass para quando nenhuma dessas alternativas der conta, e documente bem o porquê. O objetivo do módulo não é te transformar em autor de metaclasses, é te dar a leitura correta quando encontrar uma.
Teste rápido
Quando os métodos __new__ e __init__ de uma metaclass são executados?
Perguntas frequentes
- Qual a diferença entre metaclass e herança?
- Herança define de onde uma classe reaproveita atributos e métodos; é uma relação entre classes irmãs de nível. Metaclass define quem fabrica a classe, um nível acima. Uma classe pode herdar de várias bases e, ao mesmo tempo, ter uma metaclass que controla como ela nasce.
- Toda classe tem uma metaclass?
- Sim. Se você não especifica, a metaclass é type, a fábrica padrão. Quando você escreve metaclass=OutraCoisa, apenas troca a fábrica por uma personalizada. Por isso dizemos que type é a metaclass padrão de todas as classes.
- Posso usar duas metaclasses diferentes com herança múltipla?
- Não livremente. Se duas bases têm metaclasses incompatíveis, o Python levanta um erro de conflito de metaclass. A metaclass da classe filha precisa ser a mesma das bases ou uma subclasse delas. É mais uma razão para usar metaclasses com parcimônia.
- __new__ ou __init__ na metaclass, qual escolher?
- Use __new__ quando precisar inspecionar ou modificar o namespace antes de a classe existir, por exemplo alterando atributos. Use __init__ quando a classe já criada bastar, como em registros e ajustes finais. Se não precisa mudar a classe antes de criá-la, __init__ é mais simples.
- Existe alternativa mais simples que quase sempre serve?
- Sim: o gancho __init_subclass__, visto na última aula do módulo, cobre a maioria dos casos de reagir à criação de subclasses sem escrever metaclass. Decoradores de classe e descritores cobrem outros. Metaclass fica para o que nenhum deles resolve.
Fontes
Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.