types no Python: tipos do runtime

Publicado em: 06/08/2026
Tempo de leitura: 6 minutos
Código e estruturas representando tipos do runtime com o módulo types no Python

Funções, métodos, módulos, generators, frames, code objects e aliases genéricos são objetos reais no runtime do Python. O módulo types no Python reúne nomes padronizados para muitos desses tipos e oferece utilitários para criar classes dinamicamente, preparar namespaces, adaptar generators a coroutines e trabalhar com visualizações somente leitura.

Neste guia, você aprenderá a usar SimpleNamespace, MappingProxyType, MethodType, new_class(), prepare_class(), resolve_bases() e os tipos expostos pelo módulo. O conteúdo complementa nossos artigos sobre inspect no Python, bytecode com dis, symtable, contextvars e copyreg.

Por que o módulo types existe

Muitos tipos internos podem ser descobertos com type(), mas escrever código usando expressões como type(lambda: None) é pouco claro. O módulo types fornece nomes explícitos, como FunctionType, GeneratorType, CoroutineType e TracebackType.

import types

print(isinstance(lambda: None, types.FunctionType))
print(isinstance((x for x in range(3)), types.GeneratorType))

Esses nomes são úteis em introspecção, depuradores, frameworks e validações de baixo nível. Para regras de negócio, prefira protocolos e collections.abc quando o comportamento importa mais que a implementação exata.

SimpleNamespace

SimpleNamespace cria um objeto simples cujos atributos vêm de um dicionário interno.

from types import SimpleNamespace

config = SimpleNamespace(
    host="localhost",
    porta=8000,
    debug=True,
)

print(config.host)
config.porta = 9000

Ele é conveniente para resultados pequenos, configurações transitórias, mocks e agrupamento de valores. A representação mostra os atributos e a igualdade compara namespaces pelo conteúdo.

SimpleNamespace não substitui uma classe de domínio

O objeto não valida campos, não impõe tipos e aceita novos atributos livremente.

config.portta = 7000  # erro de digitação aceito

Quando invariantes, documentação, métodos ou validação importam, use dataclasses.dataclass, NamedTuple, TypedDict ou uma classe convencional.

MappingProxyType

MappingProxyType cria uma visualização dinâmica somente leitura de um mapping.

from types import MappingProxyType

origem = {"modo": "produção", "tentativas": 3}
publico = MappingProxyType(origem)

print(publico["modo"])
# publico["modo"] = "teste"  # TypeError

O proxy impede alterações pela referência pública, mas continua refletindo mudanças realizadas no mapping original.

origem["tentativas"] = 5
print(publico["tentativas"])  # 5

Portanto, ele oferece acesso somente leitura, não imutabilidade profunda.

Quando usar MappingProxyType

É útil para expor registries, metadados, configurações internas e tabelas de dispatch sem entregar uma referência mutável.

_handlers = {"json": processar_json}
handlers = MappingProxyType(_handlers)

Valores internos ainda podem ser mutáveis. Se o mapping contém listas, quem recebe o proxy pode alterar essas listas. Faça cópias ou use estruturas imutáveis quando necessário.

MethodType

MethodType vincula uma função a uma instância, criando um método ligado.

from types import MethodType

class Usuario:
    def __init__(self, nome):
        self.nome = nome


def saudar(self):
    return f"Olá, {self.nome}"

usuario = Usuario("Ana")
usuario.saudar = MethodType(saudar, usuario)
print(usuario.saudar())

Esse recurso aparece em testes, instrumentação e sistemas de plugins. Alterar instâncias dinamicamente pode dificultar type checking e manutenção; prefira composição ou subclasses quando a regra é permanente.

FunctionType e LambdaType

FunctionType representa funções definidas em Python. LambdaType é um alias para o mesmo tipo.

import types


def somar(a, b):
    return a + b

assert isinstance(somar, types.FunctionType)
assert types.LambdaType is types.FunctionType

Built-ins como len usam BuiltinFunctionType, enquanto métodos built-in podem usar BuiltinMethodType.

GeneratorType, CoroutineType e AsyncGeneratorType

O módulo nomeia objetos produzidos por funções generator e async.

import types


def numeros():
    yield 1

async def buscar():
    return 42

async def eventos():
    yield "inicio"

generator = numeros()
coroutine = buscar()
async_generator = eventos()

print(isinstance(generator, types.GeneratorType))
print(isinstance(coroutine, types.CoroutineType))
print(isinstance(async_generator, types.AsyncGeneratorType))

Coroutines criadas precisam ser aguardadas ou fechadas para evitar warnings.

types.coroutine()

types.coroutine() transforma uma função generator em uma coroutine compatível com await. Ele existe principalmente para interoperabilidade de baixo nível entre generators e runtimes assíncronos.

import types

@types.coroutine
def esperar_evento():
    resultado = yield "evento"
    return resultado

Aplicações modernas normalmente devem usar async def. O decorator é apropriado para bibliotecas que implementam protocolos assíncronos ou precisam adaptar código legado.

ModuleType

ModuleType cria objetos de módulo.

from types import ModuleType

modulo = ModuleType("meu_modulo", "Módulo criado dinamicamente")
modulo.valor = 42

print(modulo.__name__)
print(modulo.valor)

Para criar módulos que participarão do sistema de importação, a documentação oficial de importlib recomenda usar specs e importlib.util.module_from_spec(), que configura mais atributos corretamente.

Criar classes com new_class()

new_class() implementa o processo moderno de criação dinâmica de classes.

import types


def preencher(namespace):
    namespace["categoria"] = "dinâmica"

    def descrever(self):
        return self.categoria

    namespace["descrever"] = descrever

Classe = types.new_class(
    "Classe",
    bases=(object,),
    exec_body=preencher,
)

print(Classe().descrever())

O utilitário respeita metaclasses, __prepare__() e resolução de bases, sendo preferível a reproduzir manualmente todo o protocolo.

Argumentos de new_class()

O primeiro argumento é o nome; bases define classes-base; kwds contém argumentos como metaclass; e exec_body recebe o namespace preparado.

Classe = types.new_class(
    "Plugin",
    bases=(BasePlugin,),
    kwds={"metaclass": MetaPlugin},
    exec_body=lambda ns: ns.update({"versao": 1}),
)

Valide nomes, bases e metaclasses quando esses valores vêm de configuração. Criar uma classe não é uma sandbox.

prepare_class()

prepare_class() calcula a metaclass adequada e prepara o namespace antes da criação.

meta, namespace, kwds = types.prepare_class(
    "MinhaClasse",
    (Base,),
    {"metaclass": MinhaMeta},
)

namespace["atributo"] = 10
MinhaClasse = meta("MinhaClasse", (Base,), namespace, **kwds)

Ele é útil em frameworks que precisam inspecionar ou preencher o namespace entre a preparação e a construção.

resolve_bases()

Bases de classe podem não ser tipos reais, mas objetos com __mro_entries__(). resolve_bases() aplica esse protocolo.

bases_resolvidas = types.resolve_bases(bases_originais)

Isso é importante para aliases genéricos e abstrações que participam da lista de bases. Use as bases resolvidas ao chamar uma metaclass diretamente.

get_original_bases()

get_original_bases() recupera as bases declaradas antes da resolução quando essa informação foi preservada em __orig_bases__.

from typing import Generic, TypeVar

T = TypeVar("T")

class Caixa(Generic[T]):
    pass

class CaixaTexto(Caixa[str]):
    pass

print(types.get_original_bases(CaixaTexto))

Frameworks de typing podem usar isso para descobrir parâmetros genéricos. Trate a ausência de metadados como caso normal.

DynamicClassAttribute

DynamicClassAttribute cria um descriptor semelhante a property, mas permite tratamento diferente no acesso pela classe.

Ele é usado principalmente por implementações como enum. Em código comum, property costuma ser mais simples. Use o descriptor apenas quando uma metaclass ou __getattr__() de classe precisa interceptar o acesso.

CodeType

CodeType representa objetos de código compilado.

codigo = compile("x = 1", "<exemplo>", "exec")
print(isinstance(codigo, types.CodeType))

O construtor de CodeType muda entre versões e possui muitos detalhes internos. Prefira compile() e code.replace() para alterações controladas.

novo = codigo.replace(co_filename="arquivo_virtual.py")

Executar code objects continua sendo execução de código e não deve ocorrer com entrada desconhecida.

FrameType e TracebackType

FrameType representa frames de execução; TracebackType representa a cadeia de traceback de uma exceção.

try:
    1 / 0
except ZeroDivisionError as erro:
    tb = erro.__traceback__
    print(isinstance(tb, types.TracebackType))
    print(isinstance(tb.tb_frame, types.FrameType))

Frames mantêm referências a variáveis locais e podem prolongar a vida de objetos. Libere referências após diagnósticos longos.

GenericAlias e UnionType

GenericAlias representa expressões como list[int]. UnionType representa unions criadas com |.

alias = list[int]
uniao = int | str

print(isinstance(alias, types.GenericAlias))
print(isinstance(uniao, types.UnionType))

Esses objetos são úteis em introspecção de annotations, mas não aplicam validação de valores em runtime.

Tipos singleton

O módulo fornece nomes para tipos de valores especiais, como NoneType, EllipsisType e NotImplementedType.

print(isinstance(None, types.NoneType))
print(isinstance(Ellipsis, types.EllipsisType))
print(isinstance(NotImplemented, types.NotImplementedType))

Isso evita expressões como type(None) em APIs de introspecção.

Descriptors de extensões

GetSetDescriptorType e MemberDescriptorType representam descriptors frequentemente criados por extensões C e por __slots__.

class Exemplo:
    __slots__ = ("valor",)

print(isinstance(Exemplo.valor, types.MemberDescriptorType))

As implementações podem usar o mesmo tipo interno para ambos em alguns runtimes. Não dependa dessa diferença sem testar as plataformas suportadas.

Segurança e introspecção

O módulo types expõe estruturas poderosas do runtime. Criar classes, módulos, code objects ou métodos dinâmicos não valida a origem do comportamento.

Não execute funções, bases, metaclasses ou bytecode provenientes de usuários. Para plugins, defina interfaces, assinaturas, permissões e isolamento.

Erros frequentes

  • Usar SimpleNamespace para dados que exigem validação.
  • Tratar MappingProxyType como imutabilidade profunda.
  • Vincular métodos dinamicamente sem documentar.
  • Construir CodeType manualmente.
  • Misturar timestamps ou metaclasses não confiáveis.
  • Presumir que annotations validam runtime.
  • Conservar frames e tracebacks indefinidamente.
  • Usar tipos exatos quando um protocolo seria melhor.

Boas práticas

  • Use nomes de types para introspecção clara.
  • Prefira dataclasses para modelos estruturados.
  • Use proxies somente leitura para APIs públicas.
  • Crie classes dinâmicas com new_class().
  • Use module_from_spec() no sistema de importação.
  • Prefira async def a adapters legados.
  • Libere frames depois da análise.
  • Teste compatibilidade entre versões do Python.

Conclusão

O módulo types no Python dá nomes explícitos a estruturas do runtime e oferece utilitários para namespaces, mappings somente leitura, métodos ligados e criação dinâmica de classes. Ele é especialmente útil em frameworks, depuradores e ferramentas de introspecção.

Essas APIs operam perto dos mecanismos internos da linguagem. Ao preferir abstrações simples quando possível, validar metaclasses e plugins e evitar dependência de construtores instáveis, você aproveita a flexibilidade do runtime sem tornar o projeto frágil.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Conteúdo do artigo

    Artigos relacionados

    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    sched no Python: agende eventos

    Aprenda sched no Python para agendar eventos, controlar prioridades, cancelar tarefas e criar repetições com relógio monotônico.

    Ler mais

    Tempo de leitura: 8 minutos
    05/08/2026
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    atexit no Python: execute limpeza ao sair

    Aprenda atexit no Python para executar limpeza no encerramento, controlar ordem LIFO e evitar problemas com threads, sinais e exceções.

    Ler mais

    Tempo de leitura: 7 minutos
    05/08/2026
    Monitor com código binário representando análise de opcodes pickle com pickletools no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    pickletools no Python: analise pickles

    Aprenda pickletools no Python para desmontar pickles, analisar opcodes e otimizar fluxos sem executar dados não confiáveis.

    Ler mais

    Tempo de leitura: 7 minutos
    05/08/2026
    Código-fonte em tela representando análise com tokenize no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    tokenize no Python: analise código-fonte

    Aprenda tokenize no Python para ler tokens, comentários, indentação, codificação, posições e reconstruir código-fonte com segurança.

    Ler mais

    Tempo de leitura: 6 minutos
    05/08/2026
    Desenvolvedor trabalhando em automação de build e compilação de diretórios com compileall no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    compileall no Python: compile diretórios

    Aprenda compileall no Python para compilar diretórios, gerar pyc em paralelo, filtrar arquivos e controlar otimização e invalidação.

    Ler mais

    Tempo de leitura: 7 minutos
    04/08/2026
    Monitor com código binário representando geração de arquivos pyc com py_compile no Python
    Python Avançado
    Foto de perfil de Leandro Hirt da Academify

    py_compile no Python: gere arquivos pyc

    Aprenda py_compile no Python para gerar arquivos pyc, validar sintaxe e controlar otimização e invalidação por timestamp ou hash.

    Ler mais

    Tempo de leitura: 7 minutos
    04/08/2026