typing.Unpack representa a expansão estática de uma estrutura de tipos. Ele aparece em dois cenários principais: tipar argumentos nomeados recebidos por **kwargs a partir de um TypedDict e expandir uma tupla variádica baseada em TypeVarTuple. Em ambos os casos, Unpack permite que o analisador enxergue elementos individuais que, sem a anotação, ficariam escondidos dentro de uma coleção genérica.
Neste guia, você aprenderá a usar Unpack em funções, wrappers, factories, callbacks, classes genéricas e arrays tipados; entenderá Required, NotRequired, TypeVarTuple, compatibilidade de assinaturas, encaminhamento de kwargs e limites de runtime.
O problema de **kwargs genérico
def conectar(**opcoes: object) -> None:
...
conectar(host="localhost", porta=5432, ssl=True)A assinatura aceita qualquer nome e qualquer valor. O editor não sugere parâmetros, o analisador não detecta erros de digitação e chamadas inválidas parecem corretas.
TypedDict com Unpack
from typing import TypedDict, Unpack
class OpcoesConexao(TypedDict):
host: str
porta: int
def conectar(**opcoes: Unpack[OpcoesConexao]) -> None:
host = opcoes["host"]
porta = opcoes["porta"]Agora host e porta são argumentos nomeados obrigatórios. O analisador conhece seus tipos e pode rejeitar nomes extras ou valores incompatíveis.
Campos opcionais
from typing import NotRequired
class OpcoesConexao(TypedDict):
host: str
porta: int
timeout: NotRequired[float]
ssl: NotRequired[bool]Required e NotRequired definem quais kwargs são obrigatórios. O artigo sobre Required e NotRequired no Python detalha presença e nulabilidade.
Chamada correta e incorreta
conectar(host="db.local", porta=5432)
conectar(host="db.local", porta=5432, timeout=3.0)
conectar(host="db.local") # falta porta
conectar(host="db.local", porta="5432") # tipo errado
conectar(host="db.local", porta=5432, retries=2) # nome extraA validação ocorre durante análise estática. Em runtime, **kwargs continua sendo um dicionário normal.
Dentro da função
O parâmetro opcoes é tratado como o TypedDict correspondente. Chaves obrigatórias podem ser acessadas diretamente; chaves opcionais exigem teste ou valor padrão.
def conectar(**opcoes: Unpack[OpcoesConexao]) -> None:
timeout = opcoes.get("timeout", 5.0)
usar_ssl = opcoes.get("ssl", False)Encaminhando kwargs
def conectar_com_log(**opcoes: Unpack[OpcoesConexao]) -> None:
print("conectando")
conectar(**opcoes)O wrapper preserva os nomes e tipos. Se ele aceitasse apenas **opcoes: object, a relação seria perdida e o encaminhamento exigiria cast ou seria menos seguro.
Adicionar parâmetros explícitos
def conectar_com_log(
nivel: str,
**opcoes: Unpack[OpcoesConexao],
) -> None:
...Parâmetros anteriores continuam normais. Cuidado para não criar um nome explícito que também exista no TypedDict, pois a assinatura teria conflito.
Conflitos de nomes
class Opcoes(TypedDict):
nivel: str
# Evite combinar nivel explícito e Unpack[Opcoes]Cada argumento nomeado deve aparecer uma única vez. Ferramentas de tipos devem sinalizar sobreposição entre parâmetros declarados e chaves expandidas.
kwargs extras
Unpack de TypedDict normalmente descreve um conjunto fechado de nomes. Se a função realmente aceita parâmetros arbitrários adicionais, talvez TypedDict não represente a API. Considere um mapping explícito, sobrecargas, um objeto de configuração ou separar opções conhecidas de metadados livres.
Modelando callbacks
from collections.abc import Callable
class EventoKwargs(TypedDict):
usuario_id: int
acao: str
Callback = Callable[..., None]Expressar kwargs específicos em Callable pode exigir Protocol com método __call__:
from typing import Protocol
class CallbackEvento(Protocol):
def __call__(self, **dados: Unpack[EventoKwargs]) -> None: ...Assim, implementações precisam aceitar os nomes esperados.
Unpack em métodos
class Cliente:
def requisitar(self, **opcoes: Unpack[OpcoesConexao]) -> None:
...O comportamento é igual ao de funções. self não faz parte do TypedDict expandido.
Factories de objetos
class Configuracao(TypedDict, total=False):
cache: bool
timeout: float
class Servico:
def __init__(self, nome: str, **config: Unpack[Configuracao]) -> None:
...A factory oferece autocompletar para opções sem criar uma lista longa de parâmetros. Porém, parâmetros explícitos costumam ser melhores quando a API é pequena e estável.
Unpack e herança de TypedDict
class BaseHttp(TypedDict, total=False):
timeout: float
headers: dict[str, str]
class OpcoesGet(BaseHttp, total=False):
params: dict[str, str]Unpack[OpcoesGet] inclui as chaves herdadas. Hierarquias profundas dificultam descobrir a assinatura real; mantenha os tipos simples.
ReadOnly em kwargs
ReadOnly descreve escrita dentro de TypedDict, mas kwargs são construídos para cada chamada. Marcar uma opção como ReadOnly raramente traz o mesmo benefício que em registros persistentes. Use qualificadores apenas quando a semântica for clara e suportada pelo analisador.
Unpack com TypeVarTuple
O segundo grande uso é expandir uma sequência de parâmetros de tipo:
from typing import Generic, TypeVarTuple, Unpack
Dimensoes = TypeVarTuple("Dimensoes")
class Array(Generic[Unpack[Dimensoes]]):
...Uma especialização pode ter quantidade variável de dimensões:
imagem: Array[int, int, int]
matriz: Array[int, int]Os elementos após Array representam uma tupla de tipos expandida, não uma única tupla.
Sintaxe com estrela
Versões modernas permitem formas equivalentes com * em alguns contextos:
class Array[*Dimensoes]:
...Unpack[Dimensoes] continua importante para compatibilidade e para contextos onde a sintaxe estrelada não é aceita.
Tuplas variádicas
Ts = TypeVarTuple("Ts")
def adicionar_prefixo(
valores: tuple[Unpack[Ts]],
) -> tuple[str, Unpack[Ts]]:
return ("prefixo", *valores)A função preserva todos os tipos da tupla original e adiciona uma string no início.
Preservando formas
Bibliotecas numéricas podem representar eixos ou dimensões no sistema de tipos. Uma operação pode manter a forma, adicionar eixo ou remover dimensão:
Shape = TypeVarTuple("Shape")
class Tensor(Generic[Unpack[Shape]]):
...
def batch(x: Tensor[Unpack[Shape]]) -> Tensor[int, Unpack[Shape]]:
...Esse modelo é avançado e depende do suporte do analisador. Ele não valida tamanhos numéricos em runtime.
Apenas um TypeVarTuple por lista
Uma lista de parâmetros não pode conter múltiplos grupos variádicos ambíguos. O analisador precisa saber como dividir os argumentos entre eles. Estruture a API com prefixos e sufixos fixos em torno de um único grupo.
TypeVarTuple não é tuple[T, …]
tuple[T, ...] representa quantidade variável de elementos do mesmo tipo. TypeVarTuple representa quantidade variável de tipos possivelmente diferentes:
tuple[int, str, bytes]
# Ts pode representar (int, str, bytes)Unpack não executa transformação
Em runtime, a anotação não desempacota dados nem valida argumentos. O operador ** da chamada e o operador * da tupla continuam responsáveis pelo comportamento. Unpack descreve a expansão para ferramentas estáticas.
Compatibilidade de versões
Use typing_extensions.Unpack e TypeVarTuple quando necessário em versões anteriores. Verifique também a versão do mypy, pyright ou outro analisador, pois o suporte a recursos variádicos evolui.
Erros comuns
- Anotar **kwargs como TypedDict sem Unpack: isso significa que cada valor seria um TypedDict, não que as chaves foram expandidas.
- Esperar validação em runtime: kwargs continuam sendo dict.
- Permitir nomes extras sem modelá-los: Unpack descreve o conjunto conhecido.
- Criar conflito com parâmetro explícito: uma chave não pode aparecer duas vezes.
- Confundir TypeVarTuple com tupla homogênea: ele preserva tipos posicionais distintos.
- Usar variádicos em APIs simples: parâmetros explícitos podem ser mais claros.
Exemplo completo: cliente HTTP
from typing import NotRequired, TypedDict, Unpack
class OpcoesHttp(TypedDict, total=False):
timeout: float
headers: dict[str, str]
seguir_redirects: bool
tentativas: int
def get(
url: str,
**opcoes: Unpack[OpcoesHttp],
) -> bytes:
timeout = opcoes.get("timeout", 10.0)
headers = opcoes.get("headers", {})
seguir = opcoes.get("seguir_redirects", True)
tentativas = opcoes.get("tentativas", 1)
return realizar_get(url, timeout, headers, seguir, tentativas)O editor sugere quatro opções nomeadas, rejeita erros de digitação e preserva tipos. A implementação recebe um dicionário normal e aplica padrões.
Quando evitar Unpack
Prefira parâmetros explícitos quando há poucas opções estáveis, pois documentação e introspecção ficam mais simples. Use uma dataclass de configuração quando opções são compartilhadas por várias chamadas ou precisam de validação. Use Unpack quando a API já é naturalmente baseada em kwargs e você quer descrevê-la com precisão.
Conclusão
typing.Unpack torna expansões visíveis ao sistema de tipos. Com TypedDict, ele cria kwargs com nomes, tipos e obrigatoriedade conhecidos. Com TypeVarTuple, permite genéricos com quantidade variável de parâmetros posicionais.
A documentação oficial de Unpack no módulo typing detalha as formas suportadas. Use-o para preservar assinaturas e relações variádicas, mas mantenha validação de runtime e escolha uma API mais simples quando parâmetros explícitos ou objetos de configuração forem suficientes.







