typing.TypeVarTuple representa uma quantidade variável de parâmetros de tipo. Enquanto um TypeVar corresponde a um único tipo, TypeVarTuple pode capturar uma sequência heterogênea como (int, str, bytes) e reutilizá-la em outra posição. O recurso permite criar genéricos variádicos, preservar tipos posicionais de tuplas e modelar formas de arrays e tensores.
Neste guia, você aprenderá a declarar TypeVarTuple, expandi-lo com Unpack ou estrela, distinguir tuplas homogêneas de heterogêneas, adicionar prefixos e sufixos, criar classes com número variável de parâmetros, modelar dimensões e entender limites de inferência e runtime.
Limite do TypeVar comum
from typing import TypeVar
T = TypeVar("T")
def repetir(valor: T) -> tuple[T, T]:
return (valor, valor)TypeVar preserva um tipo. Ele não consegue capturar uma tupla com quantidade desconhecida de posições diferentes.
Tupla homogênea
def contar(valores: tuple[int, ...]) -> int:
return len(valores)tuple[int, ...] aceita qualquer quantidade de inteiros. Todas as posições compartilham o mesmo tipo. Isso é diferente de preservar tuple[int, str, bool] como três tipos distintos.
Declarando TypeVarTuple
from typing import TypeVarTuple
Ts = TypeVarTuple("Ts")Ts representa zero ou mais tipos posicionais. Para usá-lo em uma anotação, é necessário expandi-lo.
Expandindo com Unpack
from typing import Unpack
def identidade_tupla(
valores: tuple[Unpack[Ts]],
) -> tuple[Unpack[Ts]]:
return valoresSe a entrada é tuple[int, str], o retorno também é tuple[int, str]. Cada posição é preservada.
Sintaxe estrelada
def identidade_tupla(
valores: tuple[*Ts],
) -> tuple[*Ts]:
return valoresEm contextos modernos, *Ts é equivalente a Unpack[Ts]. A forma explícita continua útil para compatibilidade e leitura em versões anteriores.
Adicionar um prefixo
def com_nome(
valores: tuple[*Ts],
) -> tuple[str, *Ts]:
return ("registro", *valores)Uma entrada tuple[int, bool] produz tuple[str, int, bool]. O grupo variádico permanece intacto.
Adicionar um sufixo
def com_status(
valores: tuple[*Ts],
) -> tuple[*Ts, bool]:
return (*valores, True)Prefixos e sufixos fixos ajudam a modelar transformações de registros posicionais.
Remover a primeira posição
def cauda(
valores: tuple[object, *Ts],
) -> tuple[*Ts]:
primeiro, *resto = valores
return tuple(resto)A anotação descreve uma tupla com pelo menos um elemento. A implementação pode exigir cast dependendo da capacidade do analisador de relacionar a lista intermediária com a tupla variádica.
Classes genéricas variádicas
from typing import Generic
class Registro(Generic[*Ts]):
def __init__(self, valores: tuple[*Ts]) -> None:
self.valores = valoresEspecializações podem ter números diferentes de parâmetros:
linha: Registro[int, str]
pixel: Registro[int, int, int, float]A classe preserva a estrutura de cada instância no sistema de tipos.
API de zip tipada
Uma função zip genérica completa é difícil porque relaciona vários iteráveis e uma tupla de saída. TypeVarTuple permite expressar partes dessa relação, mas a inferência de iteráveis individuais pode exigir overloads ou recursos adicionais.
Modelando formas
Shape = TypeVarTuple("Shape")
class Array(Generic[*Shape]):
...Uma matriz pode ser Array[Altura, Largura] e uma imagem Array[Altura, Largura, Canais]. Os tipos podem ser marcadores de dimensão, não valores numéricos reais.
Adicionar dimensão de batch
class Batch: ...
def adicionar_batch(x: Array[*Shape]) -> Array[Batch, *Shape]:
...A operação preserva todas as dimensões existentes e adiciona uma no início. Essa relação é valiosa em bibliotecas numéricas e de machine learning.
Transposição
Reordenar um grupo variádico arbitrário é difícil. TypeVarTuple preserva uma sequência, mas não oferece operações gerais de reversão ou permutação no sistema de tipos. Para matrizes de duas dimensões, overloads ou parâmetros explícitos podem ser mais claros.
Um TypeVarTuple por lista
Uma lista de parâmetros não pode conter dois grupos variádicos sem uma forma não ambígua de separá-los:
# Ambíguo: tuple[*As, *Bs]O analisador não saberia onde termina o primeiro grupo. Use um único grupo com elementos fixos ao redor.
TypeVarTuple pode ser vazio
vazio: Registro[()]
# A sintaxe concreta varia; o conceito é uma sequência sem tipos.Funções variádicas precisam considerar o caso zero quando não exigem prefixo ou sufixo fixo. Se pelo menos uma posição é necessária, declare um elemento fixo.
Restrições e bounds
Diferentemente de TypeVar, TypeVarTuple não oferece exatamente os mesmos mecanismos de bound e constraints para cada elemento. Se todos os elementos precisam seguir uma interface, talvez uma tupla homogênea ou outra abstração seja melhor.
TypeVarTuple e Unpack
TypeVarTuple define o grupo. Unpack expande o grupo em uma lista de parâmetros ou posições. O artigo sobre Unpack no Python mostra também o uso em **kwargs.
Inferência em literais de tupla
resultado = identidade_tupla((1, "a", True))O analisador pode inferir tuple[int, str, bool]. Use assert_type() para registrar a expectativa em testes estáticos.
Listas não preservam posições
Uma lista normalmente possui um tipo de elemento comum, como list[int | str]. Ela não preserva tipos por índice. TypeVarTuple é naturalmente adequado a tuplas e listas de parâmetros genéricos, não a listas mutáveis heterogêneas.
Callable e parâmetros
TypeVarTuple não substitui ParamSpec para assinaturas de funções. ParamSpec preserva tipos de parâmetros, incluindo nomes, categorias e kwargs. TypeVarTuple preserva uma sequência posicional de tipos. Escolha conforme a relação.
Comparação com overload
Sem TypeVarTuple, uma biblioteca poderia escrever overloads para tuplas de uma, duas, três e quatro posições. O grupo variádico elimina repetição quando a transformação é uniforme para qualquer tamanho.
Runtime
TypeVarTuple não valida comprimento nem valores durante execução. Uma classe ainda precisa armazenar e verificar dados normalmente. Os parâmetros genéricos podem ser apagados ou acessíveis apenas parcialmente por introspecção.
Introspecção
get_origin() e get_args() ajudam a examinar especializações, mas objetos e classes genéricas nem sempre preservam todas as informações após construção. Não baseie invariantes de segurança apenas em argumentos de typing.
Compatibilidade
Use typing_extensions.TypeVarTuple e Unpack para versões anteriores. O suporte depende também do analisador. Atualize mypy ou pyright e teste a sintaxe escolhida.
Erros comuns
- Usar TypeVarTuple sem expansão: ele precisa aparecer como
*TsouUnpack[Ts]. - Confundir com tuple[T, …]: TypeVarTuple preserva tipos diferentes por posição.
- Criar dois grupos variádicos: a divisão fica ambígua.
- Esperar validação de forma em runtime: é uma relação estática.
- Usar no lugar de ParamSpec: assinaturas de callables precisam de nomes e categorias.
- Modelar detalhes que o analisador não suporta: simplifique a API quando necessário.
Exemplo completo: pipeline de registros
from typing import Generic, TypeVarTuple
Campos = TypeVarTuple("Campos")
class Linha(Generic[*Campos]):
def __init__(self, dados: tuple[*Campos]) -> None:
self.dados = dados
def numerar(linha: Linha[*Campos]) -> Linha[int, *Campos]:
return Linha((1, *linha.dados))
def marcar(linha: Linha[*Campos]) -> Linha[*Campos, bool]:
return Linha((*linha.dados, True))
entrada = Linha(("Ana", 42.0))
numerada = numerar(entrada)
marcada = marcar(numerada)O tipo evolui de Linha[str, float] para Linha[int, str, float] e depois Linha[int, str, float, bool]. Cada transformação conserva as posições anteriores.
Testes estáticos
from typing import assert_type
assert_type(numerada.dados, tuple[int, str, float])
assert_type(marcada.dados, tuple[int, str, float, bool])Esses testes protegem a inferência durante mudanças na implementação ou nas anotações.
Quando evitar TypeVarTuple
Use uma dataclass ou NamedTuple quando os campos possuem nomes e significado estável. Use tuple homogênea quando todos os elementos compartilham tipo. Use ParamSpec para wrappers de função. Use TypeVarTuple quando a quantidade de posições varia e a relação precisa preservar cada tipo.
Conclusão
TypeVarTuple estende genéricos Python para sequências variáveis de tipos. Ele preserva tuplas heterogêneas, cria classes com vários parâmetros e modela transformações de forma sem escrever dezenas de overloads.
A documentação oficial de TypeVarTuple no módulo typing define as regras. Use-o com Unpack ou estrela, mantenha um único grupo variádico por lista e confirme o comportamento com testes estáticos nos analisadores suportados.







