Módulo 11 - Metaclasses e descritores

Tudo é objeto: até as classes

9 min de leitura · por Cesar Gargiulo, revisado pela equipe ValorFinal e GuardiaSec · Atualizado em 01/07/2026

Velocidade

O que você vai aprender

  • Compreender que uma classe em Python também é um objeto.
  • Ver que type é a classe das classes (o tipo dos tipos).
  • Usar type() com três argumentos para criar uma classe em tempo de execução.
  • Preparar o terreno para entender o que é uma metaclass.

A classe também é um objeto

No Intermediário você aprendeu a criar objetos a partir de classes: uma classe Conta produz contas, cada uma um objeto. O que talvez tenha passado despercebido é que a própria Conta também é um objeto. Ela tem um tipo, ocupa um lugar na memória, pode ser guardada numa variável e passada para uma função como qualquer valor. Essa é a primeira virada de chave deste módulo: classe não é uma construção mágica do compilador, é um objeto que existe em tempo de execução e que você pode manipular.

class Conta:
    pass

# A classe e um objeto: da para guardar numa variavel
fabrica = Conta
c = fabrica()  # cria uma conta a partir da variavel

# E da para descobrir o tipo de cada coisa
print(type(c))        # <class '__main__.Conta'>
print(type(Conta))    # <class 'type'>
print(type(int))      # <class 'type'>
print(type(type))     # <class 'type'>

type(objeto) devolve a classe; type(classe) devolve type, a classe das classes.

Repare no resultado: o tipo de uma conta é Conta, mas o tipo de Conta é type. O mesmo vale para int, str e qualquer classe embutida. Todas são instâncias de type. É como uma pirâmide: os objetos comuns são instâncias das suas classes, e as classes são instâncias de type. No topo, type é instância de si mesma, o que fecha o modelo de objetos da linguagem de forma elegante.

type() como fábrica de classes

Se toda classe é um objeto criado por type, então usar a palavra class é só uma forma conveniente de pedir a type que fabrique um objeto-classe. Você pode fazer isso na mão. Chamada com três argumentos, type(nome, bases, atributos) cria uma classe nova: o nome como texto, uma tupla com as classes-mãe e um dicionário com métodos e atributos. O resultado é indistinguível de uma classe declarada com class.

# Estas duas formas produzem classes equivalentes.

# Forma comum, com a palavra class:
class Pato:
    patas = 2
    def grasnar(self):
        return "quack"

# Forma explicita, chamando type() como fabrica:
def grasnar(self):
    return "quack"

PatoDinamico = type("PatoDinamico", (), {"patas": 2, "grasnar": grasnar})

d = PatoDinamico()
print(d.patas)      # 2
print(d.grasnar())  # quack
print(type(d))      # <class '__main__.PatoDinamico'>

type(nome, bases, atributos) fabrica uma classe idêntica à declarada com class.

A palavra class

  • Sintaxe declarativa, legível
  • Nome e corpo escritos no código
  • O jeito de sempre, para 99% dos casos
  • Por baixo, chama type mesmo assim

A chamada type(...)

  • Sintaxe imperativa, em tempo de execução
  • Nome, bases e atributos como argumentos
  • Útil para gerar classes dinamicamente
  • Revela o que a palavra class faz por dentro

Na prática você quase nunca vai escrever type() na mão para criar classes; a palavra class é mais clara e é o certo a fazer. O valor de saber disso é conceitual: entender que a criação de uma classe é um evento em tempo de execução, que passa por type, é o que torna as metaclasses compreensíveis. Uma metaclass, como você verá na próxima aula, é apenas uma forma de personalizar essa fábrica.

Por que isso importa

Você pode passar anos escrevendo Python excelente sem nunca pensar em type como fábrica. Então por que aprender isso? Porque o modelo de objetos da linguagem só faz sentido de verdade quando você enxerga essa camada. Frameworks que você usa todo dia, de ORMs a bibliotecas de validação, se apoiam nesse mecanismo para transformar declarações de classe em comportamento. Quando você entende que a classe é um objeto construído por type, deixa de ver esses frameworks como mágica e passa a ler o que eles realmente fazem.

Vale reforçar o tom que guia o módulo inteiro: este é o poder mais bruto que Python oferece, e com ele vem a responsabilidade de não abusar. Saber que type fabrica classes não é um convite para gerar classes dinamicamente a torto e a direito. É uma lente para entender a linguagem e ler código de bibliotecas maduras. Na esmagadora maioria dos seus programas, a palavra class continua sendo a resposta certa, e o conhecimento desta aula fica no fundo, sustentando o resto.

Teste rápido

Em Python, qual é o resultado de type(int)?

Perguntas frequentes

Se tudo é objeto, funções também são objetos?
Sim. Funções são objetos de primeira classe: você pode guardá-las em variáveis, passá-las como argumento e devolvê-las de outras funções. Foi exatamente isso que tornou os decoradores possíveis. Classes seguem a mesma lógica, um passo acima.
Vou precisar usar type() com três argumentos no dia a dia?
Quase nunca. A palavra class é mais clara e é a escolha certa em praticamente todos os casos. Conhecer a forma type(nome, bases, atributos) serve para entender o que a linguagem faz por dentro e para ler bibliotecas que geram classes dinamicamente.
Qual a diferença entre type(x) com um argumento e com três?
Com um argumento, type(x) devolve o tipo do objeto x, funcionando como uma consulta. Com três argumentos, type(nome, bases, atributos) cria uma classe nova. São dois usos da mesma função embutida, algo raro na linguagem, por razões históricas.
O que significa dizer que type é instância de si mesma?
type é a classe que cria as classes, mas ela também é uma classe, então precisa ter um tipo. Esse tipo é a própria type. Essa autorreferência fecha o modelo de objetos sem precisar de uma torre infinita de metaclasses acima.
Isso é específico do Python ou existe em outras linguagens?
A ideia de classe como objeto existe em várias linguagens dinâmicas, como Smalltalk e Ruby. Em linguagens estáticas como Java a classe também é representada por um objeto em tempo de execução, mas o modelo é menos maleável do que o de Python.

Fontes

Seu progresso fica salvo neste aparelho. Assinantes sincronizam entre os aparelhos.