types.new_class en Python: clases dinámicas

Publicado el: 30/08/2026
Tempo de leitura: 3 minutos
A person typing on a laptop with a Python programming book visible, capturing technology and learning.

types.new_class() crea clases dinámicamente siguiendo las reglas principales de una declaración class. Selecciona la metaclase apropiada, prepara el namespace y ejecuta un callback que añade atributos, métodos y metadatos antes de construir el tipo final.

Es útil en frameworks, ORMs, generadores de modelos, sistemas de plugins y APIs basadas en schemas. Para casos simples, type() puede ser suficiente; new_class es valiosa cuando importan metaclases, __prepare__ o bases dinámicas.

Firma

types.new_class(name, bases=(), kwds=None, exec_body=None)

name define el nombre, bases contiene las clases base, kwds representa opciones del encabezado y exec_body recibe el namespace preparado.

Ejemplo básico

from types import new_class

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

    def describir(self):
        return self.categoria

    namespace["describir"] = describir

Producto = new_class("Producto", (), {}, completar)
print(Producto().describir())

El callback modifica el namespace antes de la creación.

Equivalencia conceptual

class Producto:
    categoria = "dinámica"

    def describir(self):
        return self.categoria

Una declaración normal es preferible cuando la estructura se conoce al escribir el programa. La generación dinámica debe reservarse para definiciones determinadas en runtime.

Usar una clase base

class Modelo:
    def guardar(self):
        print("guardando", type(self).__name__)

def cuerpo(ns):
    ns["tabla"] = "clientes"

Cliente = new_class("Cliente", (Modelo,), exec_body=cuerpo)

La clase generada participa normalmente en herencia, MRO, descriptors y super().

Metaclase explícita

class Meta(type):
    def __new__(mcls, nombre, bases, namespace):
        namespace["registrada"] = True
        return super().__new__(mcls, nombre, bases, namespace)

Generada = new_class(
    "Generada",
    (),
    {"metaclass": Meta},
    lambda ns: ns.update(valor=10),
)

El diccionario kwds corresponde a keywords del encabezado de clase. La opción metaclass participa en la creación y no se convierte en un atributo ordinario.

__prepare__ y namespaces especiales

Las metaclases pueden implementar __prepare__ para devolver un mapping especializado. new_class respeta este protocolo, a diferencia de una solución simple que crea un diccionario y llama a type.

types.prepare_class

Para controlar todas las etapas, types.prepare_class() calcula la metaclase y devuelve el namespace preparado. new_class combina esos pasos en una interfaz cómoda.

Bases dinámicas y __mro_entries__

Objetos usados como bases pueden ofrecer __mro_entries__ y ser reemplazados por clases reales. El módulo types también incluye resolve_bases. Este mecanismo aparece en genéricos y frameworks avanzados.

Métodos con closures

def crear_modelo(nombre, campos):
    def cuerpo(ns):
        ns["__annotations__"] = dict(campos)

        def __repr__(self):
            valores = ", ".join(
                f"{campo}={getattr(self, campo, None)!r}"
                for campo in campos
            )
            return f"{nombre}({valores})"

        ns["__repr__"] = __repr__

    return new_class(nombre, (), exec_body=cuerpo)

Ten cuidado con la captura de variables de loops al generar varios métodos.

Definir __module__ y __qualname__

Las clases públicas generadas necesitan metadatos coherentes para documentación, errores y serialización.

def cuerpo(ns):
    ns["__module__"] = __name__
    ns["__doc__"] = "Modelo generado dinámicamente."

Pickle e importabilidad

Pickle normalmente necesita que la clase sea accesible mediante un nombre importable. Una clase creada dentro de una función puede tener que registrarse en el namespace del módulo.

Aplicar decorators

La clase devuelta puede pasarse a dataclasses.dataclass, registradores u otros decorators. Los frameworks que inspeccionan durante la creación pueden requerir atributos dentro de exec_body.

Seguridad

No conviertas schemas no confiables directamente en bases, metaclases, identificadores o código ejecutable. Valida nombres, usa listas permitidas y evita exec cuando una construcción estructurada sea suficiente.

new_class frente a type

type(nombre, bases, namespace) es conciso cuando el namespace ya está disponible. new_class es mejor cuando necesitas reproducir el proceso de definición, incluida la selección de metaclase y el namespace preparado.

Errores comunes

  • Generar una clase cuando una dataclass u objeto simple basta.
  • Olvidar __module__ y perjudicar pickle o documentación.
  • Capturar mal variables de loops.
  • Confiar en bases o metaclases externas.
  • No probar MRO, herencia e introspección.

Buenas prácticas

Centraliza la generación en una factory, valida schemas, usa nombres deterministas, conserva metadatos y prueba las clases como APIs públicas. Consulta las guías internas sobre módulo types, programación orientada a objetos y dataclasses.

Conclusión

types.new_class ofrece una forma estructurada de generar clases en runtime respetando metaclases, namespaces preparados y herencia. Es adecuada para infraestructura basada en definiciones dinámicas.

Fuentes externas

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    High-angle view of woman coding on a laptop, with a Python book nearby. Ideal for programming and tech content.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    partialmethod: crea métodos especializados en Python

    Aprende partialmethod en Python para métodos especializados con binding correcto, menos wrappers y APIs de dominio más claras.

    Ler mais

    Tempo de leitura: 3 minutos
    30/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    inspect.getmembers_static: atributos sin ejecutar

    Usa inspect.getmembers_static en Python para listar atributos sin ejecutar properties, descriptors ni resolución dinámica no deseada.

    Ler mais

    Tempo de leitura: 3 minutos
    30/08/2026
    Close-up view of a computer screen displaying code in a software development environment.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    DynamicClassAttribute: descriptors y acceso dinámico

    Entiende DynamicClassAttribute en Python, descriptors, acceso por clase e instancia, metaclases, Enum e introspección segura.

    Ler mais

    Tempo de leitura: 3 minutos
    30/08/2026
    Vibrant close-up of artistically decorated acoustic guitars with floral patterns.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    UserList en Python: secuencias personalizadas

    Aprende UserList en Python para crear secuencias personalizadas con validación, normalización, mutaciones y APIs predecibles.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    Close-up of a laptop screen with code and a coffee mug, perfect for tech abstract themes.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    UserDict en Python: mappings personalizados

    Aprende UserDict en Python para crear mappings personalizados con validación, normalización, composición y mutaciones predecibles.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026
    Close-up of hands typing on a laptop keyboard, Python book in sight, coding in progress.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    itertools.accumulate: sumas y estados acumulados

    Aprende itertools.accumulate en Python para sumas, saldos, récords, transiciones de estado y pipelines lazy eficientes.

    Ler mais

    Tempo de leitura: 2 minutos
    30/08/2026