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 = 9000Ele é 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 aceitoQuando 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" # TypeErrorO proxy impede alterações pela referência pública, mas continua refletindo mudanças realizadas no mapping original.
origem["tentativas"] = 5
print(publico["tentativas"]) # 5Portanto, 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.FunctionTypeBuilt-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 resultadoAplicaçõ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
SimpleNamespacepara dados que exigem validação. - Tratar
MappingProxyTypecomo imutabilidade profunda. - Vincular métodos dinamicamente sem documentar.
- Construir
CodeTypemanualmente. - 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 defa 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.





