types en Python: tipos del runtime

Publicado el: 06/08/2026
Tempo de leitura: 5 minutos
Código y estructuras que representan tipos del runtime con el módulo types en Python

Funciones, métodos, módulos, generators, frames, code objects y aliases genéricos son objetos reales en el runtime de Python. El módulo types en Python proporciona nombres estándar para muchas de estas estructuras y utilidades para crear clases dinámicas, preparar namespaces, adaptar generators a coroutines y exponer mappings de solo lectura.

Esta guía explica SimpleNamespace, MappingProxyType, MethodType, new_class(), prepare_class(), resolve_bases() y los tipos del runtime expuestos por el módulo. Complementa nuestros artículos sobre inspect en Python, bytecode con dis, symtable, contextvars y copyreg.

Por qué existe el módulo types

Muchos tipos internos pueden descubrirse con type(), pero expresiones como type(lambda: None) son poco claras. El módulo ofrece nombres explícitos como FunctionType, GeneratorType, CoroutineType y TracebackType.

import types

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

Estos nombres son útiles en introspección, depuradores, frameworks y validaciones de bajo nivel. La lógica de negocio debería preferir protocolos y collections.abc cuando importa el comportamiento más que el tipo exacto.

SimpleNamespace

SimpleNamespace crea un objeto sencillo cuyos atributos se almacenan en un diccionario interno.

from types import SimpleNamespace

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

print(config.host)
config.puerto = 9000

Es útil para resultados pequeños, configuración temporal, mocks y agrupación de valores. Su representación muestra atributos y la igualdad compara el contenido del namespace.

SimpleNamespace no sustituye un modelo de dominio

El objeto no valida campos, no impone tipos y acepta atributos nuevos libremente.

config.puertoo = 7000  # typo aceptado

Cuando importan invariantes, documentación, métodos o validación, usa dataclass, NamedTuple, TypedDict o una clase ordinaria.

MappingProxyType

MappingProxyType crea una vista dinámica de solo lectura de un mapping.

from types import MappingProxyType

origen = {"modo": "producción", "intentos": 3}
publico = MappingProxyType(origen)

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

El proxy impide cambios mediante la referencia pública, pero refleja actualizaciones realizadas sobre el mapping original.

origen["intentos"] = 5
print(publico["intentos"])

Ofrece acceso de solo lectura, no inmutabilidad profunda.

Cuándo usar MappingProxyType

Es útil para exponer registries, metadatos, configuración interna y tablas de dispatch sin entregar una referencia mutable.

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

Los valores anidados todavía pueden ser mutables. Copia o congela las estructuras internas cuando sea necesario.

MethodType

MethodType vincula una función a una instancia y produce un método ligado.

from types import MethodType

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


def saludar(self):
    return f"Hola, {self.nombre}"

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

Este recurso aparece en tests, instrumentación y plugins. Para comportamiento permanente, composición o subclasses suelen ser más claras.

FunctionType y LambdaType

FunctionType representa funciones definidas en Python. LambdaType es un alias del mismo tipo.

import types


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

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

Built-ins como len usan BuiltinFunctionType, y métodos built-in pueden usar BuiltinMethodType.

GeneratorType, CoroutineType y AsyncGeneratorType

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))

Las coroutines creadas deben esperarse o cerrarse para evitar warnings.

types.coroutine()

types.coroutine() transforma una función generator en una coroutine compatible con await. Su uso principal es la interoperabilidad de bajo nivel entre generators y sistemas async.

import types

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

Las aplicaciones modernas normalmente deberían usar async def. El decorator sigue siendo útil para runtimes y adapters legados.

ModuleType

ModuleType crea objetos de módulo.

from types import ModuleType

modulo = ModuleType("mi_modulo", "Módulo creado dinámicamente")
modulo.valor = 42

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

Para módulos que participan en imports, la documentación oficial de importlib recomienda specs y importlib.util.module_from_spec(), que inicializa más atributos correctamente.

Crear clases con new_class()

new_class() implementa el protocolo moderno de creación dinámica.

import types


def llenar(namespace):
    namespace["categoria"] = "dinámica"

    def describir(self):
        return self.categoria

    namespace["describir"] = describir

Dinamica = types.new_class(
    "Dinamica",
    bases=(object,),
    exec_body=llenar,
)

print(Dinamica().describir())

La función respeta metaclasses, __prepare__() y resolución de bases.

Parámetros de new_class()

El primer argumento es el nombre; bases contiene las bases; kwds puede incluir metaclass; y exec_body recibe el namespace preparado.

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

Valida nombres, bases y metaclasses que provienen de configuración. Crear una clase dinámica no es una sandbox.

prepare_class()

prepare_class() calcula la metaclass y prepara el namespace antes de construir la clase.

meta, namespace, palabras = types.prepare_class(
    "MiClase",
    (Base,),
    {"metaclass": MiMeta},
)

namespace["atributo"] = 10
MiClase = meta("MiClase", (Base,), namespace, **palabras)

Los frameworks pueden inspeccionar o llenar el namespace entre preparación y construcción.

resolve_bases()

Las bases pueden incluir objetos con __mro_entries__() en lugar de tipos reales. resolve_bases() aplica ese protocolo.

resueltas = types.resolve_bases(bases_originales)

Esto importa para aliases genéricos y abstracciones utilizadas en la lista de bases.

get_original_bases()

get_original_bases() recupera las bases declaradas antes de la resolución cuando existe __orig_bases__.

from typing import Generic, TypeVar

T = TypeVar("T")

class Caja(Generic[T]):
    pass

class CajaTexto(Caja[str]):
    pass

print(types.get_original_bases(CajaTexto))

Los frameworks de typing pueden recuperar parámetros genéricos. La ausencia de metadatos debe tratarse como normal.

DynamicClassAttribute

DynamicClassAttribute crea un descriptor similar a property, pero permite manejo diferente al acceder desde la clase.

Lo utiliza, por ejemplo, enum. El código de aplicación normalmente debería preferir property.

CodeType

CodeType representa objetos de código compilado.

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

El constructor cambia entre versiones y expone detalles internos. Prefiere compile() y code.replace().

nuevo = codigo.replace(co_filename="archivo_virtual.py")

Ejecutar un code object sigue siendo ejecutar código.

FrameType y TracebackType

FrameType representa frames y TracebackType la cadena de traceback.

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

Los frames retienen variables locales y pueden prolongar la vida de objetos. Libera referencias después del diagnóstico.

GenericAlias y UnionType

GenericAlias representa expresiones como list[int]. UnionType representa unions creadas con |.

alias = list[int]
union = int | str

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

Estos objetos apoyan introspección de annotations, pero no validan valores en runtime.

Tipos singleton

El módulo ofrece nombres como NoneType, EllipsisType y NotImplementedType.

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

Esto evita expresiones como type(None).

Descriptors de extensiones

GetSetDescriptorType y MemberDescriptorType representan descriptors creados frecuentemente por extensiones C y __slots__.

class Ejemplo:
    __slots__ = ("valor",)

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

Algunos runtimes pueden usar el mismo tipo interno para ambas categorías. Prueba las implementaciones soportadas.

Seguridad e introspección

El módulo expone estructuras poderosas del runtime. Crear clases, módulos, métodos, metaclasses o code objects no valida su origen.

No ejecutes funciones, bases, metaclasses o bytecode proporcionados por usuarios. Los plugins necesitan interfaces, autorización y aislamiento.

Errores frecuentes

  • Usar SimpleNamespace para datos que necesitan validación.
  • Tratar MappingProxyType como inmutabilidad profunda.
  • Añadir métodos dinámicos sin documentar.
  • Construir CodeType manualmente.
  • Aceptar bases o metaclasses no confiables.
  • Suponer que annotations validan valores.
  • Conservar frames indefinidamente.
  • Usar tipos exactos cuando un protocolo es mejor.

Buenas prácticas

  • Usa nombres de types para introspección clara.
  • Prefiere dataclasses para modelos estructurados.
  • Expón proxies de solo lectura.
  • Crea clases dinámicas con new_class().
  • Usa module_from_spec() para imports.
  • Prefiere async def.
  • Libera frames después del análisis.
  • Prueba compatibilidad entre versiones.

Conclusión

El módulo types en Python da nombres explícitos a estructuras del runtime y utilidades para namespaces, mappings de solo lectura, métodos ligados y clases dinámicas. Es especialmente útil en frameworks, depuradores e introspección.

Estas APIs operan cerca de los mecanismos internos. Prefiriendo abstracciones simples, validando plugins y metaclasses y evitando constructores inestables, puedes aprovechar la flexibilidad del runtime sin volver frágil la aplicación.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    sched en Python: programa eventos

    Aprende sched en Python para programar eventos, controlar prioridades, cancelar tareas y crear recurrencia con reloj monotónico.

    Ler mais

    Tempo de leitura: 7 minutos
    05/08/2026
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    atexit en Python: ejecuta limpieza al salir

    Aprende atexit en Python para ejecutar limpieza al salir, controlar el orden LIFO y evitar problemas con threads, señales y

    Ler mais

    Tempo de leitura: 7 minutos
    05/08/2026
    Monitor con código binario que representa análisis de opcodes pickle con pickletools en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    pickletools en Python: analiza pickles

    Aprende pickletools en Python para desmontar pickles, analizar opcodes y optimizar flujos sin ejecutar datos no confiables.

    Ler mais

    Tempo de leitura: 6 minutos
    05/08/2026
    Código fuente en pantalla que representa análisis con tokenize en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    tokenize en Python: analiza código fuente

    Aprende tokenize en Python para inspeccionar tokens, comentarios, indentación, codificación, posiciones y reconstruir código de forma segura.

    Ler mais

    Tempo de leitura: 7 minutos
    05/08/2026
    Desarrollador trabajando en automatización de build y compilación de directorios con compileall en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    compileall en Python: compila directorios

    Aprende compileall en Python para compilar directorios, generar pyc en paralelo, filtrar rutas y controlar optimización e invalidación.

    Ler mais

    Tempo de leitura: 6 minutos
    04/08/2026
    Monitor con código binario que representa generación de archivos pyc con py_compile en Python
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    py_compile en Python: genera archivos pyc

    Aprende py_compile en Python para generar archivos pyc, validar sintaxis y controlar optimización e invalidación por timestamp o hash.

    Ler mais

    Tempo de leitura: 6 minutos
    04/08/2026