Python 3.12: melhorias no typing e perf counters
O Python 3.12 continua a tradição de melhorias incrementais focadas em performance e developer experience. As principais novidades são type parameter syntax, better f-strings, e novas ferramentas de profiling.
Type Parameter Syntax
O Python 3.12 introduz uma sintaxe mais limpa para definir generics (PEP 695):
# Antes do 3.12
from typing import TypeVar, Generic
T = TypeVar("T")
class Stack(Generic[T]):
def __init__(self) -> None:
self.items: list[T] = []
def push(self, item: T) -> None:
self.items.append(item)
def pop(self) -> T:
return self.items.pop()
# Python 3.12: sintaxe nativa
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:
return self.items.pop()
Para funções:
# Antes
from typing import TypeVar
T = TypeVar("T")
def first[T](lst: list[T]) -> T | None:
return lst[0] if lst else None
# Python 3.12
def first[T](lst: list[T]) -> T | None:
return lst[0] if lst else None
Com constraints:
# Type com bound
def max_value[T: Comparable](a: T, b: T) -> T:
return a if a > b else b
# Type com constraints explícitos
type Number = int | float | complex
type statement
Novo statement para definir type aliases:
# Antes
from typing import TypeAlias
Vector: TypeAlias = list[float]
Matrix: TypeAlias = list[Vector]
# Python 3.12
type Vector = list[float]
type Matrix = list[Vector]
Funciona com generics:
type Result[T] = T | Exception
type Pair[T, U] = tuple[T, U]
Better f-strings
F-strings agora suportam expressões mais complexas:
# Multiline f-strings
mensagem = f"""
Usuário: {user.nome}
E-mail: {user.email}
Status: {"Ativo" if user.ativo else "Inativo"}
"""
# Comentários dentro de f-strings
valor = 42
print(f"O valor é {
valor # Isto é um comentário
}")
# Backslashes (não era possível antes)
print(f"Nova linha: {
'linha1\nlinha2'
}")
Perf counters
Novas funções de alta resolução para profiling:
import time
# time.perf_counter() já existia
# time.perf_counter_ns() retorna em nanossegundos
inicio = time.perf_counter_ns()
# ... código ...
fim = time.perf_counter_ns()
print(f"Tempo: {(fim - inicio) / 1_000_000:.2f}ms")
# time.monotonic_ns()
# Garantido monotônico (não volta atrás com ajustes de relógio)
itertools.batched
Nova função para processar dados em lotes:
from itertools import batched
dados = range(10)
for batch in batched(dados, 3):
print(batch)
# (0, 1, 2)
# (3, 4, 5)
# (6, 7, 8)
# (9,)
# Útil para processar APIs em lotes
def enviar_em_lote(ids):
for batch in batched(ids, 100):
api.enviar_lote(batch)
pathlib.Path.walk()
Walking em diretórios de forma mais eficiente:
from pathlib import Path
# Antes: os.walk()
import os
for dirpath, dirnames, filenames in os.walk("/projeto"):
...
# Python 3.12: Path.walk()
for dirpath, dirnames, filenames in Path("/projeto").walk():
for f in filenames:
print(dirpath / f)
asyncio.TaskGroup aprimorado
Melhor tratamento de erros em TaskGroups:
import asyncio
async def tarefa(n):
await asyncio.sleep(1)
if n == 3:
raise ValueError(f"Erro na tarefa {n}")
return n
async def main():
try:
async with asyncio.TaskGroup() as tg:
tasks = [tg.create_task(tarefa(i)) for i in range(5)]
except* ValueError as eg:
for exc in eg.exceptions:
print(f"Capturado: {exc}")
asyncio.run(main())
Subinterpreters
Suporte experimental a subinterpreters (PEP 684), permitindo verdadeiro paralelismo com GIL separado por interpreter:
# Experimental — para extensões C principalmente
import _xxsubinterpreters as interpreters
interp = interpreters.create()
interpreters.run_string(interp, "print('Olá de outro interpreter!')")
interpreters.destroy(interp)
Melhorias no traceback
# Python 3.12 mostra sugestões para typos
class MinhaClasse:
def metodo_correto(self):
pass
obj = MinhaClasse()
obj.metodo_coreto() # AttributeError: 'MinhaClasse' object has no attribute 'metodo_coreto'. Did you mean: 'metodo_correto'?
Outras melhorias
datetime:datetime.fromtimestamp()com timezone mais precisahashlib: suporte a SHA-3 via OpenSSL (mais rápido)sqlite3: suporte aautocommitos:os.waitstatus_to_exitcode()no Windows- Buffer protocol: suporte a
__buffer__em Python puro
Conclusão
O Python 3.12 é uma release que poli e refina. A type parameter syntax elimina boilerplate de generics, o type statement torna aliases mais claros, e itertools.batched é uma daquelas funções que você não sabia que precisava até usar.
Combine com o 3.10 (match) e 3.11 (performance) para ter o melhor Python possível.
Caso eu tenha falado alguma besteira, por favor, agradecerei correções e sugestões.