Fundamentos Teóricos das Type Hints no Python

A PEP 483 estabelece a base teórica para o sistema de anotações de tipo no Python, introdzuido na versão 3.5. Este documento explora os conceitos fundamentais que permitem a verificação estática de tipos em uma linguagem intrinsicamente dinâmica.

Tipos e Relações de Subtipagem

Um tipo é definido como um conjunto de valores e as operações aplicáveis a esses valores. A subtipagem ocorre quando um tipo T1 é considerado um subtipo de T2 se todos os valores de T1 também forem válidos em T2, e T1 suportar todas as operações de T2 (podendo ter adicionais).

Existem duas abordagens principais para declarar subtipagem:

  • Subtiapgem Nominal: Baseada na hierarquia de herança de classes.
  • Subtipagem Estrutural: Baseada na presença de métodos e atributos específicos, independentemente da herança.
class Veiculo:
    def mover(self) -> None: ...

class Carro(Veiculo):
    def mover(self) -> None: ...
    def buzinhar(self) -> None: ...

# Carro é um subtipo de Veiculo (Nominal)

Tipagem Gradual e Consistência

A tipagem gradual permite anotar apenas partes do código, mesclando tipagem estática e dinâmica. A compatibilidade é regida pela relação de "consistência", que difere da subtipagem estrita ao introduzir o tipo Any:

  • Se T1 é subtipo de T2, T1 é consistente com T2.
  • Any é consistente com qualquer tipo.
  • Qualquer tipo é consistente com Any.
class Forma: ...
class Circulo(Forma): ...

elemento: Forma = Circulo()  # Válido (Subtipagem)
dinamico: Any = obter_dados()
elemento = dinamico          # Válido (Consistência com Any)

Construtores de Tipos Fundamentais

O módulo typing fornece blocos de construção para tipos complexos:

  • Union: Aceita múltiplos tipos. Union[int, str].
  • Optional: Atalho para Union[T, None].
  • Tuple: Define tuplas de tamanho fixo ou variável. Tuple[int, float] ou Tuple[str, ...].
  • Callable: Tipa funções e callables. Callable[[int, str], bool].

Tipos Genéricos e Variáveis de Tipo

Genéricos permitem parametrizar classes e funções com tipos. Utiliza-se TypeVar para criar variáveis de tipo.

from typing import TypeVar, Generic, Sequence

Item = TypeVar('Item')

class Pilha(Generic[Item]):
    def __init__(self) -> None:
        self._dados: list[Item] = []
    
    def empilhar(self, valor: Item) -> None:
        self._dados.append(valor)
        
    def desempilhar(self) -> Item:
        return self._dados.pop()

def obter_ultimo(seq: Sequence[Item]) -> Item:
    return seq[-1]

Variância: Covariância, Contravariância e Invariância

A variância define como a subtipagem de tipos copmlexos se relaciona com a subtipagem de seus parâmetros:

  • Covariante: A direção da subtipagem é preservada. Comum em estruturas imutáveis ou de somente leitura.
  • Contravariante: A direção da subtipagem é invertida. Típico de parâmetros de entrada em callables.
  • Invariante: Não há relação de subtipagem. Padrão para estruturas mutáveis.
T_co = TypeVar('T_co', covariant=True)
T_contra = TypeVar('T_contra', contravariant=True)

class CacheLeitura(Generic[T_co]):  # Covariante
    def obter(self) -> T_co: ...

class ProcessadorDados(Generic[T_contra]):  # Contravariante
    def consumir(self, dado: T_contra) -> None: ...

class BufferMutavel(Generic[Item]):  # Invariante
    def ler(self) -> Item: ...
    def escrever(self, valor: Item) -> None: ...

Recursos Práticos

Para facilitar o uso diário, o sistema de tipos suporta:

  • Aliases de Tipo: Coordenada = Tuple[float, float].
  • Referências Diretivas: Uso de strings para classes ainda não definidas, como def comparar(self, outro: 'No') -> int.
  • Conversão Explícita: Uso de cast(Tipo, objeto) para forçar uma tipagem específica sem verificação em tempo de execução.

Tags: Python TypeHints PEP483 StaticTyping TypingModule

Publicado em 7-24 07:44