As dicas de tipo Python transformam a forma como você escreve, lê e mantém o código Python. Adicionadas no Python 3.5 e melhoradas drasticamente até a versão 3.12+, as dicas de tipo agora são uma prática padrão no desenvolvimento profissional em Python. Este guia cobre tudo, desde padrões básicos até padrões avançados.
📋 Table of Contents
Por que as dicas de tipo são importantes em 2026
Python permanece digitado dinamicamente em tempo de execução, mas as dicas de tipo fornecem:
- Inteligência de IDE— preenchimento automático, definição, refatoração em PyCharm e VS Code
- Análise estática– mypy e Pyright detectam bugs antes do tempo de execução
- Documentação— assinaturas de funções explicam o que entra e o que sai
- Confiança em escala— refatoração segura em grandes bases de código
Anotações Básicas
from typing import Optional, Union
from datetime import datetime
# Variable annotations
name: str = "Alice"
age: int = 30
active: bool = True
scores: list[float] = [9.5, 8.7, 9.2]
config: dict[str, str] = {"env": "prod", "region": "us-east-1"}
# Function annotations
def greet(name: str, greeting: str = "Hello") -> str:
return f"{greeting}, {name}!"
def find_user(user_id: int) -> dict[str, str] | None:
# Python 3.10+ union syntax (| instead of Union[])
...
# None return type
def log(message: str) -> None:
print(f"[LOG] {message}")
Coleções e genéricos
from typing import Sequence, Mapping, Iterator, Generator
from collections.abc import Callable
# Built-in generics (Python 3.9+)
def first(items: list[int]) -> int | None:
return items[0] if items else None
def merge(a: dict[str, int], b: dict[str, int]) -> dict[str, int]:
return {**a, **b}
# Sequence — more general than list
def count_items(items: Sequence[str]) -> int:
return len(items)
# Callable type
def apply(func: Callable[[int, int], int], a: int, b: int) -> int:
return func(a, b)
result = apply(lambda x, y: x + y, 3, 4) # 7
# Generator type
def fibonacci() -> Generator[int, None, None]:
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# TypeVar for generic functions
from typing import TypeVar
T = TypeVar("T")
def identity(value: T) -> T:
return value
def first_item(items: list[T]) -> T | None:
return items[0] if items else None
TypedDict e classes de dados
from typing import TypedDict, Required, NotRequired
from dataclasses import dataclass, field
# TypedDict — typed dictionaries
class UserDict(TypedDict):
id: int
name: str
email: str
class PartialUser(TypedDict, total=False):
id: int
name: str
email: str
# With Required/NotRequired (Python 3.11+)
class Config(TypedDict):
host: Required[str]
port: Required[int]
debug: NotRequired[bool]
# Dataclass — cleaner than TypedDict for classes
@dataclass
class Product:
id: int
name: str
price: float
tags: list[str] = field(default_factory=list)
active: bool = True
def apply_discount(self, percent: float) -> "Product":
return Product(
id=self.id,
name=self.name,
price=self.price * (1 - percent / 100),
tags=self.tags,
active=self.active
)
# frozen=True for immutability
@dataclass(frozen=True)
class Point:
x: float
y: float
Protocolo – Subtipagem Estrutural
Os protocolos definem interfaces sem herança:
from typing import Protocol, runtime_checkable
@runtime_checkable
class Drawable(Protocol):
def draw(self) -> None: ...
def get_area(self) -> float: ...
class Circle:
def __init__(self, radius: float):
self.radius = radius
def draw(self) -> None:
print(f"Drawing circle r={self.radius}")
def get_area(self) -> float:
import math
return math.pi * self.radius ** 2
class Rectangle:
def __init__(self, width: float, height: float):
self.width = width
self.height = height
def draw(self) -> None:
print(f"Drawing rect {self.width}x{self.height}")
def get_area(self) -> float:
return self.width * self.height
def render_all(shapes: list[Drawable]) -> None:
for shape in shapes:
shape.draw()
print(f"Area: {shape.get_area():.2f}")
# Works without inheritance — structural compatibility
shapes: list[Drawable] = [Circle(5.0), Rectangle(3.0, 4.0)]
render_all(shapes)
Tipos literais e finais
from typing import Literal, Final, TypeAlias
# Literal — restrict to specific values
def set_direction(direction: Literal["north", "south", "east", "west"]) -> None:
print(f"Moving {direction}")
set_direction("north") # OK
set_direction("up") # mypy error!
# Final — constants that cannot be reassigned
MAX_RETRIES: Final = 3
BASE_URL: Final[str] = "https://api.example.com"
# TypeAlias — named type aliases (Python 3.10+)
Vector: TypeAlias = list[float]
Matrix: TypeAlias = list[Vector]
JSON: TypeAlias = dict[str, "JSONValue"]
JSONValue: TypeAlias = str | int | float | bool | None | list["JSONValue"] | JSON
ParamSpec e TypeVarTuple (avançado)
from typing import ParamSpec, TypeVar, Callable
import functools
import time
P = ParamSpec("P")
R = TypeVar("R")
# Type-safe decorator that preserves signature
def retry(max_attempts: int = 3):
def decorator(func: Callable[P, R]) -> Callable[P, R]:
@functools.wraps(func)
def wrapper(*args: P.args, **kwargs: P.kwargs) -> R:
for attempt in range(max_attempts):
try:
return func(*args, **kwargs)
except Exception as e:
if attempt == max_attempts - 1:
raise
time.sleep(2 ** attempt)
raise RuntimeError("unreachable")
return wrapper
return decorator
@retry(max_attempts=3)
def fetch_data(url: str, timeout: int = 30) -> dict:
import requests
return requests.get(url, timeout=timeout).json()
Configuração mypy e Pyright
# pyproject.toml
[tool.mypy]
python_version = "3.12"
strict = true
warn_return_any = true
warn_unused_ignores = true
no_implicit_reexport = true
# Pyright (pyrightconfig.json or pyproject.toml)
[tool.pyright]
pythonVersion = "3.12"
typeCheckingMode = "strict"
reportMissingTypeStubs = false
Tipo de padrões de estreitamento
from typing import assert_never
type Shape = Circle | Rectangle | Triangle # Python 3.12 type statement
def get_area(shape: Shape) -> float:
match shape:
case Circle(radius=r):
return 3.14159 * r * r
case Rectangle(width=w, height=h):
return w * h
case Triangle(base=b, height=h):
return 0.5 * b * h
case _ as unreachable:
assert_never(unreachable) # exhaustiveness check
Resumo
As dicas do tipo Python em 2026 são essenciais para o desenvolvimento profissional. Use-os em todos os novos códigos, habilite a verificação estrita de mypy/Pyright e aproveite o Protocolo para digitação de pato. O impacto no desempenho do tempo de execução é zero – os tipos são apagados no tempo de execução.
🔗 Share this article
✍️ Leave a Comment