Sintaxe de Parâmetros de Tipo no Python 3.12

Como a PEP 695 do Python 3.12 simplifica a criação de funções, classes e aliases genéricos com a sintaxe def func[T](...), eliminando a necessidade de TypeVar e Generic.

Antes do Python 3.12, escrever uma função ou classe genérica exigia declarar um TypeVar à parte, em escopo de módulo, e importar Generic para usá-lo em uma classe. Funcionava, mas era verboso e o TypeVar ficava "solto", compartilhado por qualquer código que o importasse. A sintaxe de parâmetros de tipo (PEP 695) resolve isso: agora dá para declarar o tipo genérico direto na definição da função, classe ou alias, usando colchetes, sem import nenhum.

Como era antes

O jeito clássico precisa de um TypeVar declarado fora da função, mais Generic[T] na classe:

from typing import TypeVar, Generic

T = TypeVar("T")

def primeiro(itens: list[T]) -> T:
    return itens[0]

class Pilha(Generic[T]):
    def __init__(self) -> None:
        self._itens: list[T] = []

    def empilhar(self, item: T) -> None:
        self._itens.append(item)

    def desempilhar(self) -> T:
        return self._itens.pop()

O T aqui é uma variável de módulo comum — nada impede que outra função reaproveite o mesmo T com um significado diferente, e não existe nenhum vínculo explícito entre o TypeVar e quem o usa.

A nova sintaxe

Com a PEP 695, o parâmetro de tipo entra entre colchetes logo após o nome da função ou classe, e some sozinho: não precisa de TypeVar nem de Generic:

def primeiro[T](itens: list[T]) -> T:
    return itens[0]

class Pilha[T]:
    def __init__(self) -> None:
        self._itens: list[T] = []

    def empilhar(self, item: T) -> None:
        self._itens.append(item)

    def desempilhar(self) -> T:
        return self._itens.pop()

O T agora é escopado à própria função ou classe — não vaza para o resto do módulo, e duas funções podem usar [T] sem nenhum conflito entre si.

Restringindo o tipo com bound

É possível limitar quais tipos são aceitos usando : depois do nome do parâmetro, equivalente ao antigo bound= do TypeVar:

from dataclasses import dataclass

@dataclass
class Produto:
    nome: str
    preco: float

def mais_caro[T: Produto](itens: list[T]) -> T:
    return max(itens, key=lambda item: item.preco)

Aqui T só aceita Produto ou subclasses; passar uma lista de int, por exemplo, seria rejeitado por ferramentas como mypy ou Pyright.

Aliases de tipo genéricos

A mesma PEP também trouxe a palavra-chave type para declarar aliases, inclusive genéricos, avaliados de forma preguiçosa (lazy), o que permite referências recursivas:

type Talvez[T] = T | None

type Arvore[T] = T | list["Arvore[T]"]

def buscar[T](valor: Talvez[T], padrao: T) -> T:
    return valor if valor is not None else padrao

Quando usar

Cuidados

Essa sintaxe é reconhecida apenas em tempo de análise estática e pelo próprio interpretador ao fazer parsing — ela não muda o comportamento em tempo de execução, que continua sem checagem de tipos (Python permanece dinamicamente tipado). Código escrito com a sintaxe nova só roda em Python 3.12+; para dar suporte a versões anteriores na mesma base de código, ainda é preciso usar o TypeVar tradicional ou uma ferramenta de conversão automática, como a regra UP047 do Ruff.

Compatibilidade

A sintaxe de parâmetros de tipo (PEP 695) foi introduzida no Python 3.12, lançado em outubro de 2023, e é suportada por mypy, Pyright e Ruff nas versões mais recentes dessas ferramentas.

documentação oficial

Conclusão

A PEP 695 não muda o que é possível fazer com generics em Python, mas torna a sintaxe muito mais direta: menos import, menos boilerplate e um escopo de tipo que finalmente corresponde ao escopo do código. Para quem já usa TypeVar e Generic no dia a dia, é uma migração natural assim que o suporte ao Python 3.12+ for garantido.

Tecnologia:
python

Deixe seu Comentário!

Comentário
Nome
Email