Unpack en Python: kwargs y tipos variádicos

Publicado el: 29/08/2026
Tempo de leitura: 4 minutos
Close-up of a laptop screen with code and a coffee mug, perfect for tech abstract themes.

typing.Unpack representa la expansión estática de una estructura de tipos. Tiene dos usos principales: describir argumentos nombrados recibidos mediante **kwargs a partir de un TypedDict y expandir una tupla variádica basada en TypeVarTuple. En ambos casos, Unpack permite que el analizador vea elementos individuales ocultos dentro de una colección genérica.

Esta guía cubre kwargs tipados, opciones obligatorias y opcionales, wrappers, métodos, factories, protocolos invocables, TypeVarTuple, tuplas variádicas, genéricos que conservan formas, limitaciones de runtime y compatibilidad.

El problema de **kwargs genérico

def conectar(**opciones: object) -> None:
    ...

conectar(host="localhost", puerto=5432, ssl=True)

La firma acepta cualquier nombre y cualquier valor. El editor no sugiere opciones, los errores de escritura parecen válidos y los tipos incorrectos son difíciles de detectar.

TypedDict con Unpack

from typing import TypedDict, Unpack

class OpcionesConexion(TypedDict):
    host: str
    puerto: int


def conectar(**opciones: Unpack[OpcionesConexion]) -> None:
    host = opciones["host"]
    puerto = opciones["puerto"]

host y puerto son argumentos nombrados obligatorios. El analizador conoce sus tipos y rechaza nombres desconocidos.

Opciones opcionales

from typing import NotRequired

class OpcionesConexion(TypedDict):
    host: str
    puerto: int
    timeout: NotRequired[float]
    ssl: NotRequired[bool]

Required y NotRequired determinan qué kwargs debe proporcionar el consumidor. Consulta Required y NotRequired en Python.

Llamadas válidas e inválidas

conectar(host="db.local", puerto=5432)
conectar(host="db.local", puerto=5432, timeout=3.0)

conectar(host="db.local")                  # falta puerto
conectar(host="db.local", puerto="5432") # tipo incorrecto
conectar(host="db.local", puerto=5432, reintentos=2) # nombre extra

Estas comprobaciones son estáticas. En runtime, opciones sigue siendo un diccionario normal.

Dentro de la función

def conectar(**opciones: Unpack[OpcionesConexion]) -> None:
    timeout = opciones.get("timeout", 5.0)
    usar_ssl = opciones.get("ssl", False)

Las claves obligatorias se acceden directamente. Las opcionales necesitan prueba, get() o un valor predeterminado.

Reenviar kwargs

def conectar_con_log(**opciones: Unpack[OpcionesConexion]) -> None:
    print("conectando")
    conectar(**opciones)

El wrapper conserva nombres y tipos. Anotarlo como **opciones: object perdería la relación.

Añadir parámetros explícitos

def conectar_con_log(
    nivel: str,
    **opciones: Unpack[OpcionesConexion],
) -> None:
    ...

Los parámetros normales pueden aparecer antes. Evita declarar un parámetro cuyo nombre también exista en el TypedDict.

Conflictos de nombres

class Opciones(TypedDict):
    nivel: str

# No combines nivel explícito con Unpack[Opciones]

Cada keyword debe aparecer una sola vez en la firma efectiva. Los analizadores deberían detectar solapamientos.

kwargs extra arbitrarios

Unpack de TypedDict normalmente describe un conjunto cerrado. Si la función acepta nombres adicionales, tal vez TypedDict no represente la API. Considera un mapping de metadatos, overloads, un objeto de configuración o un parámetro separado para extras.

Protocolos invocables

from typing import Protocol

class DatosEvento(TypedDict):
    usuario_id: int
    accion: str

class CallbackEvento(Protocol):
    def __call__(self, **datos: Unpack[DatosEvento]) -> None: ...

Un Protocol puede expresar un callback con argumentos nombrados específicos. Las implementaciones deben ofrecer una firma compatible.

Unpack en métodos

class Cliente:
    def solicitar(self, **opciones: Unpack[OpcionesConexion]) -> None:
        ...

El comportamiento es el mismo. self está separado del conjunto expandido.

Factories de objetos

class Configuracion(TypedDict, total=False):
    cache: bool
    timeout: float

class Servicio:
    def __init__(self, nombre: str, **config: Unpack[Configuracion]) -> None:
        ...

Esto ofrece autocompletado sin una lista extensa. Los parámetros explícitos suelen ser mejores cuando la API es pequeña y estable.

Herencia de TypedDict

class BaseHttp(TypedDict, total=False):
    timeout: float
    headers: dict[str, str]

class OpcionesGet(BaseHttp, total=False):
    params: dict[str, str]

Unpack[OpcionesGet] incluye claves heredadas. Las jerarquías profundas dificultan descubrir la firma real.

ReadOnly y kwargs

ReadOnly describe escritura sobre campos de TypedDict, pero los kwargs se construyen en cada llamada. Suele ser más útil en registros persistentes que en bolsas de opciones.

Unpack con TypeVarTuple

from typing import Generic, TypeVarTuple, Unpack

Dimensiones = TypeVarTuple("Dimensiones")

class Array(Generic[Unpack[Dimensiones]]):
    ...

Las especializaciones pueden contener cantidades diferentes de dimensiones:

imagen: Array[int, int, int]
matriz: Array[int, int]

Los argumentos representan una tupla de tipos expandida, no un único tipo tuple.

Sintaxis con estrella

class Array[*Dimensiones]:
    ...

Python moderno permite esta forma en algunos contextos. Unpack[Dimensiones] sigue siendo importante para compatibilidad.

Tuplas variádicas

Ts = TypeVarTuple("Ts")

def agregar_prefijo(
    valores: tuple[Unpack[Ts]],
) -> tuple[str, Unpack[Ts]]:
    return ("prefijo", *valores)

La función conserva cada tipo posicional de la tupla original y añade una string al principio.

Conservar formas

Shape = TypeVarTuple("Shape")

class Tensor(Generic[Unpack[Shape]]):
    ...

def batch(x: Tensor[Unpack[Shape]]) -> Tensor[int, Unpack[Shape]]:
    ...

Bibliotecas numéricas pueden modelar operaciones que conservan o añaden ejes. Es una relación estática y no valida tamaños numéricos en runtime.

Un grupo variádico por lista

Varios TypeVarTuple sin restricciones serían ambiguos. El analizador no sabría cómo dividir los argumentos. Diseña prefijos y sufijos fijos alrededor de un solo grupo variádico.

TypeVarTuple frente a tuple[T, …]

tuple[T, ...] representa cantidad variable de valores del mismo tipo. TypeVarTuple conserva tipos posicionales distintos:

tuple[int, str, bytes]
# Ts puede representar (int, str, bytes)

Unpack no trabaja en runtime

La anotación no desempaca datos ni valida argumentos. Los operadores normales ** y * realizan la expansión. Unpack solo describe esa relación a herramientas estáticas.

Compatibilidad

Usa typing_extensions.Unpack y TypeVarTuple en versiones anteriores. Comprueba también la versión del analizador porque el soporte de genéricos variádicos evoluciona.

Errores comunes

  • Anotar **kwargs con TypedDict sin Unpack: significaría que cada valor es un TypedDict.
  • Esperar validación de runtime: kwargs sigue siendo dict.
  • Aceptar nombres arbitrarios sin modelarlos: Unpack describe claves conocidas.
  • Solapar nombres explícitos y expandidos: un keyword no puede aparecer dos veces.
  • Confundir TypeVarTuple con tupla homogénea: conserva posiciones diferentes.
  • Usar variádicos en APIs simples: los parámetros explícitos pueden ser más claros.

Ejemplo completo: cliente HTTP

from typing import TypedDict, Unpack

class OpcionesHttp(TypedDict, total=False):
    timeout: float
    headers: dict[str, str]
    seguir_redirects: bool
    reintentos: int


def get(
    url: str,
    **opciones: Unpack[OpcionesHttp],
) -> bytes:
    timeout = opciones.get("timeout", 10.0)
    headers = opciones.get("headers", {})
    seguir = opciones.get("seguir_redirects", True)
    reintentos = opciones.get("reintentos", 1)
    return realizar_get(url, timeout, headers, seguir, reintentos)

El editor sugiere cuatro nombres, rechaza errores y conserva tipos. La implementación recibe un diccionario normal y aplica valores predeterminados.

Cuándo evitar Unpack

Prefiere parámetros explícitos cuando hay pocas opciones estables. Usa una dataclass de configuración cuando se comparten o necesitan validación. Usa Unpack cuando la API es naturalmente kwargs y quieres describirla con precisión.

Conclusión

typing.Unpack hace visibles las expansiones al sistema de tipos. Con TypedDict crea kwargs con nombres, tipos y presencia conocidos. Con TypeVarTuple habilita genéricos con cantidad variable de parámetros posicionales.

La documentación oficial de Unpack en Python define las formas soportadas. Úsalo para conservar firmas y relaciones variádicas, manteniendo validación de runtime y eligiendo APIs más simples cuando sean suficientes.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    A developer typing code on a laptop with a Python book beside in an office.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    runtime_checkable en Python: Protocol runtime

    Aprende runtime_checkable en Python para comprobar Protocol con isinstance, entender límites y diseñar contratos estructurales seguros.

    Ler mais

    Tempo de leitura: 5 minutos
    29/08/2026
    Person holding Python logo sticker with blurred background, highlighting programming focus.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    Required y NotRequired: campos opcionales en TypedDict

    Aprende Required y NotRequired en Python para controlar claves obligatorias y opcionales de TypedDict sin confundir ausencia con None.

    Ler mais

    Tempo de leitura: 5 minutos
    29/08/2026
    Ball python slithering on a sunlit gravel pathway outdoors.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    ReadOnly en Python: protege campos TypedDict

    Aprende ReadOnly en Python para proteger campos TypedDict, modelar contratos estables y evitar escrituras accidentales.

    Ler mais

    Tempo de leitura: 5 minutos
    29/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

    TypeAliasType en Python: alias en runtime

    Aprende TypeAliasType en Python para crear alias explícitos, inspeccionarlos en runtime y modelar APIs genéricas reutilizables.

    Ler mais

    Tempo de leitura: 6 minutos
    29/08/2026
    A person reads 'Python for Unix and Linux System Administration' indoors.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    overload en Python: firmas precisas

    Aprende typing.overload en Python para firmas precisas con Literal, None, genéricos, métodos y retornos dependientes de argumentos.

    Ler mais

    Tempo de leitura: 6 minutos
    29/08/2026
    A person typing on a laptop with a Python programming book visible, capturing technology and learning.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    ClassVar en Python: separa clase e instancia

    Aprende ClassVar en Python para separar atributos de clase e instancia en dataclasses, registries, caches, herencia y contadores.

    Ler mais

    Tempo de leitura: 6 minutos
    29/08/2026