🌐 Detecting your location…
📢 Advertisement — Configure AdSense in Appearance → Customize → AdSense Settings

Aprofundamento do sistema de tipo Python 2026: PEP 695, protocolos e genéricos

⏱️5 min read  ·  923 words

O sistema de tipos do Python amadureceu significativamente em 2026 com o Python 3.12+. PEP 695 (sintaxe do parâmetro de tipo), PEP 696 (padrões TypeVar) e o novotypedeclaração torna os genéricos do Python mais legíveis. Este mergulho profundo cobre padrões de tipo avançados que desenvolvedores Python experientes devem conhecer.

Nova sintaxe: instrução de tipo (Python 3.12+)

# Old way (still works)
from typing import TypeAlias, TypeVar
Vector = list[float]
T = TypeVar("T")

# New syntax (Python 3.12+, much cleaner)
type Vector = list[float]
type Matrix = list[Vector]
type JSON = str | int | float | bool | None | list["JSON"] | dict[str, "JSON"]

# Generic type alias
type Stack[T] = list[T]
type Pair[T, U] = tuple[T, U]
type Callback[T] = callable[[T], None]

# Use them
def push[T](stack: Stack[T], item: T) -> Stack[T]:
    return [*stack, item]

numbers: Stack[int] = [1, 2, 3]
result = push(numbers, 4)

Classes e funções genéricas (Python 3.12+)

# Old TypeVar syntax (still valid)
from typing import TypeVar
T = TypeVar("T")
def first(items: list[T]) -> T | None:
    return items[0] if items else None

# New syntax (PEP 695)
def first[T](items: list[T]) -> T | None:
    return items[0] if items else None

def map_list[T, U](items: list[T], fn: callable[[T], U]) -> list[U]:
    return [fn(item) for item in items]

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

    def push(self, item: T) -> None:
        self._items.append(item)

    def pop(self) -> T:
        if not self._items:
            raise IndexError("Stack is empty")
        return self._items.pop()

    def peek(self) -> T | None:
        return self._items[-1] if self._items else None

    def __len__(self) -> int:
        return len(self._items)

# Usage
stack: Stack[str] = Stack()
stack.push("hello")
stack.push("world")
print(stack.pop())  # "world"

# Constrained TypeVar
def sort_items[T: (int, str, float)](items: list[T]) -> list[T]:
    return sorted(items)

TypeVar com padrão (PEP 696 – Python 3.13+)

from typing import TypeVar

# TypeVar with default
T = TypeVar("T", default=str)

class Container[T = str]:
    def __init__(self, value: T) -> None:
        self.value = value

    def get(self) -> T:
        return self.value

# T defaults to str if not specified
c1: Container = Container("hello")  # T = str (default)
c2: Container[int] = Container(42)  # T = int (explicit)

Protocolos – Subtipagem Estrutural

from typing import Protocol, runtime_checkable
from collections.abc import Sequence

@runtime_checkable
class Sizeable(Protocol):
    def __len__(self) -> int: ...

@runtime_checkable
class Comparable[T](Protocol):
    def __lt__(self, other: T) -> bool: ...
    def __le__(self, other: T) -> bool: ...
    def __gt__(self, other: T) -> bool: ...
    def __ge__(self, other: T) -> bool: ...

# Any class with __len__ satisfies Sizeable — no inheritance needed
def count_items(collection: Sizeable) -> int:
    return len(collection)

print(count_items([1, 2, 3]))        # works: list has __len__
print(count_items({"a": 1}))        # works: dict has __len__
print(count_items("hello"))          # works: str has __len__

# isinstance check (requires @runtime_checkable)
print(isinstance([1, 2], Sizeable))  # True

# Protocol with methods
class Serializable(Protocol):
    def to_json(self) -> str: ...
    def to_dict(self) -> dict: ...

    @classmethod
    def from_json(cls, json_str: str) -> "Serializable": ...

Sobrecargas – Múltiplas Assinaturas

from typing import overload

@overload
def process(x: int) -> int: ...
@overload
def process(x: str) -> str: ...
@overload
def process(x: list[int]) -> list[int]: ...

def process(x):
    if isinstance(x, int):
        return x * 2
    elif isinstance(x, str):
        return x.upper()
    elif isinstance(x, list):
        return [item * 2 for item in x]

# Type checker knows the return type based on input type
result_int: int = process(5)      # type checker: int
result_str: str = process("hi")   # type checker: str
result_list: list[int] = process([1, 2, 3])  # type checker: list[int]

Padrões avançados TypedDict

from typing import TypedDict, Required, NotRequired

# Partial TypedDict — some required, some optional
class UserCreate(TypedDict):
    name: Required[str]
    email: Required[str]
    password: Required[str]
    role: NotRequired[str]   # optional

# Inheritance
class UserUpdate(TypedDict, total=False):
    name: str
    email: str
    role: str

# Nested TypedDict
class Address(TypedDict):
    street: str
    city: str
    country: str
    zip_code: NotRequired[str]

class UserWithAddress(TypedDict):
    id: int
    name: str
    address: Address

# Use in function signatures
def create_user(user: UserCreate) -> int:
    return db.insert("users", user)

def update_user(user_id: int, updates: UserUpdate) -> bool:
    return db.update("users", user_id, updates)

ParamSpec — Decoradores de tipo seguro

from typing import ParamSpec, TypeVar, Callable
import functools

P = ParamSpec("P")
R = TypeVar("R")

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
            raise RuntimeError("unreachable")
        return wrapper
    return decorator

@retry(max_attempts=3)
def fetch_data(url: str, timeout: int = 30) -> dict:
    return requests.get(url, timeout=timeout).json()

# Type checker knows: fetch_data(url: str, timeout: int = 30) -> dict
# The decorator is fully transparent to the type system

O sistema de tipos do Python em 2026 com a nova sintaxe PEP 695 é significativamente mais legível do que a sintaxe baseada em TypeVar. Os principais padrões: use protocolos para digitação estrutural, ParamSpec para decoradores com segurança de tipo, TypedDict para dicionários digitados, @overload para assinaturas múltiplas e a nova instrução de tipo para aliases limpos. Execute pyright –strict ou mypy –strict para impor esses padrões.

✍️ Leave a Comment

Your email address will not be published. Required fields are marked *

🌐 Read in:🇬🇧 English🇩🇪 Deutsch🇧🇷 Português🇸🇦 العربية🇮🇳 हिन्दी🇧🇩 বাংলা