TypeVarTuple en Python: genéricos variádicos

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

typing.TypeVarTuple representa una cantidad variable de parámetros de tipo. Un TypeVar normal captura un solo tipo, mientras TypeVarTuple puede capturar una secuencia heterogénea como (int, str, bytes) y reutilizarla en otra posición. Esto habilita genéricos variádicos, transformaciones de tuplas que conservan posiciones y modelos de arrays con forma.

Esta guía cubre declaraciones, Unpack, sintaxis con estrella, prefijos y sufijos, clases genéricas, dimensiones, límites de inferencia, comparación con ParamSpec, runtime, introspección, compatibilidad y pruebas.

El límite de TypeVar

from typing import TypeVar

T = TypeVar("T")

def repetir(valor: T) -> tuple[T, T]:
    return (valor, valor)

TypeVar conserva un tipo. No puede capturar una cantidad desconocida de posiciones con tipos diferentes.

Tuplas homogéneas

def contar(valores: tuple[int, ...]) -> int:
    return len(valores)

tuple[int, ...] acepta cualquier cantidad de enteros. Todas las posiciones comparten tipo. No conserva tuple[int, str, bool] como tres tipos separados.

Declarar TypeVarTuple

from typing import TypeVarTuple

Ts = TypeVarTuple("Ts")

Ts representa cero o más tipos posicionales. Debe expandirse al usarlo.

Expandir con Unpack

from typing import Unpack

def identidad_tupla(
    valores: tuple[Unpack[Ts]],
) -> tuple[Unpack[Ts]]:
    return valores

Una entrada tuple[int, str] produce el mismo tipo de salida. Cada posición se conserva.

Sintaxis con estrella

def identidad_tupla(valores: tuple[*Ts]) -> tuple[*Ts]:
    return valores

En contextos modernos, *Ts equivale a Unpack[Ts]. La forma explícita sigue siendo útil para compatibilidad.

Añadir prefijo

def con_nombre(
    valores: tuple[*Ts],
) -> tuple[str, *Ts]:
    return ("registro", *valores)

Una entrada tuple[int, bool] se convierte en tuple[str, int, bool].

Añadir sufijo

def con_estado(
    valores: tuple[*Ts],
) -> tuple[*Ts, bool]:
    return (*valores, True)

Los elementos fijos alrededor del grupo modelan transformaciones uniformes.

Eliminar la primera posición

def cola(
    valores: tuple[object, *Ts],
) -> tuple[*Ts]:
    primero, *resto = valores
    return tuple(resto)

La anotación exige al menos un elemento. Algunos analizadores pueden necesitar ayuda para relacionar la lista intermedia con la tupla variádica.

Clases genéricas variádicas

from typing import Generic

class Registro(Generic[*Ts]):
    def __init__(self, valores: tuple[*Ts]) -> None:
        self.valores = valores

Las especializaciones pueden tener números diferentes de parámetros:

fila: Registro[int, str]
pixel: Registro[int, int, int, float]

La clase conserva la estructura posicional de cada instancia.

Relaciones tipo zip

Una función zip completamente genérica relaciona varios iterables con una tupla de salida. TypeVarTuple expresa parte de esa relación, pero la inferencia de iterables individuales puede requerir overloads.

Modelar formas

Shape = TypeVarTuple("Shape")

class Array(Generic[*Shape]):
    ...

Una matriz puede ser Array[Alto, Ancho] y una imagen Array[Alto, Ancho, Canales]. Son marcadores de tipo, no tamaños numéricos de runtime.

Añadir dimensión batch

class Batch: ...

def agregar_batch(x: Array[*Shape]) -> Array[Batch, *Shape]:
    ...

La operación conserva todas las dimensiones existentes y añade una al principio.

Límites de transposición

TypeVarTuple conserva una secuencia, pero no ofrece inversión o permutación general a nivel de tipos. Para matrices 2D, parámetros explícitos u overloads pueden ser más claros.

Un TypeVarTuple por lista

# Ambiguo: tuple[*As, *Bs]

El analizador no sabría dónde termina el primer grupo. Usa un solo grupo con elementos fijos alrededor.

El grupo puede estar vacío

TypeVarTuple puede capturar cero tipos. Si la API requiere al menos una posición, añade un prefijo o sufijo fijo en la anotación.

Restricciones

TypeVarTuple no ofrece exactamente los mismos bounds y constraints por elemento que TypeVar. Si todos los elementos deben compartir una interfaz, una tupla homogénea puede ser mejor.

TypeVarTuple y Unpack

TypeVarTuple define el grupo y Unpack lo expande. Consulta Unpack en Python para kwargs tipados y otras expansiones.

Inferencia de literales

resultado = identidad_tupla((1, "a", True))

El analizador puede inferir tuple[int, str, bool]. Usa assert_type() para proteger la expectativa.

Las listas no conservan posiciones

Una lista suele tener un tipo común como list[int | str]. No conserva un tipo diferente por índice. TypeVarTuple encaja mejor con tuplas y listas de parámetros genéricos.

Parámetros de Callable

TypeVarTuple no sustituye ParamSpec. ParamSpec conserva nombres, categorías y kwargs de funciones. TypeVarTuple conserva una secuencia posicional de tipos.

Comparación con overloads

Sin TypeVarTuple, una biblioteca podría escribir overloads para tuplas de una, dos, tres y cuatro posiciones. El grupo variádico elimina repetición cuando la transformación es uniforme.

Runtime

TypeVarTuple no valida longitudes ni valores durante ejecución. Las clases deben imponer invariantes normalmente. Los argumentos genéricos pueden borrarse o estar disponibles parcialmente.

Introspección

get_origin() y get_args() ayudan a examinar especializaciones, pero las instancias no siempre conservan toda la información. No bases seguridad en metadatos de typing.

Compatibilidad

Usa typing_extensions.TypeVarTuple y Unpack en versiones anteriores. El soporte del analizador también importa; prueba con versiones modernas de mypy o pyright.

Errores comunes

  • Usar TypeVarTuple sin expandir: escribe *Ts o Unpack[Ts].
  • Confundir con tuple[T, …]: conserva tipos distintos por posición.
  • Crear dos grupos variádicos: la división es ambigua.
  • Esperar validación de forma en runtime: la relación es estática.
  • Reemplazar ParamSpec: las firmas necesitan más información.
  • Modelar más de lo soportado: simplifica la API.

Ejemplo completo: pipeline de registros

from typing import Generic, TypeVarTuple

Campos = TypeVarTuple("Campos")

class Fila(Generic[*Campos]):
    def __init__(self, datos: tuple[*Campos]) -> None:
        self.datos = datos


def numerar(fila: Fila[*Campos]) -> Fila[int, *Campos]:
    return Fila((1, *fila.datos))


def marcar(fila: Fila[*Campos]) -> Fila[*Campos, bool]:
    return Fila((*fila.datos, True))

entrada = Fila(("Ana", 42.0))
numerada = numerar(entrada)
marcada = marcar(numerada)

El tipo evoluciona de Fila[str, float] a Fila[int, str, float] y luego Fila[int, str, float, bool].

Pruebas estáticas

from typing import assert_type

assert_type(numerada.datos, tuple[int, str, float])
assert_type(marcada.datos, tuple[int, str, float, bool])

Estas pruebas protegen la inferencia durante cambios.

Cuándo evitar TypeVarTuple

Usa dataclass o NamedTuple cuando los campos tienen nombres estables. Usa tupla homogénea cuando comparten tipo. Usa ParamSpec para wrappers de función. Usa TypeVarTuple cuando varía el número de posiciones y cada tipo debe conservarse.

Conclusión

TypeVarTuple extiende los genéricos a secuencias variables de tipos. Conserva tuplas heterogéneas, crea clases con varios parámetros y modela transformaciones de forma sin decenas de overloads.

La documentación oficial de TypeVarTuple en Python define las reglas. Expándelo con Unpack o estrella, mantén un grupo variádico por lista y verifica el comportamiento con pruebas estáticas.

Compartilhe:

Facebook
WhatsApp
Twitter
LinkedIn

Contenido del artículo

    Artículos relacionados

    Striking image of a red-bellied python showcasing its vibrant scales in dramatic lighting.
    Python Avanzado
    Foto de perfil de Leandro Hirt da Academify

    LiteralString en Python: cadenas confiables

    Aprende LiteralString en Python para restringir SQL, templates y comandos a cadenas confiables y reducir riesgos de inyección.

    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

    dataclass_transform en Python: clases generadas

    Aprende dataclass_transform en Python para tipar decorators, clases base y metaclases que generan campos, __init__ y métodos.

    Ler mais

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

    assert_type y reveal_type: prueba inferencia de tipos

    Aprende assert_type y reveal_type en Python para inspeccionar inferencia, probar APIs tipadas y evitar regresiones estáticas.

    Ler mais

    Tempo de leitura: 4 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

    get_type_hints en Python: lee anotaciones

    Aprende get_type_hints en Python para resolver referencias futuras, conservar Annotated e inspeccionar funciones y clases con seguridad.

    Ler mais

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

    Unpack en Python: kwargs y tipos variádicos

    Aprende typing.Unpack en Python para tipar **kwargs con TypedDict, expandir tuplas variádicas y conservar firmas precisas.

    Ler mais

    Tempo de leitura: 4 minutos
    29/08/2026