Fiecare limbaj are funcționalități pe care le descoperi la un an după ce aveai nevoie de ele, iar reacția e mereu aceeași: „stai, asta a fost aici tot timpul?” Iată lista mea pentru Python.
Dataclasses (3.7+)
Înainte să aflu de dataclasses, scriam __init__, __repr__ și __eq__ de mână pentru fiecare container de date. Pierdere totală de timp.
from dataclasses import dataclass
@dataclass
class Trade:
symbol: str
price: float
quantity: int
side: str = "buy" # valoare implicită
Atât. Primești __init__, __repr__, __eq__ și opțional ordering, gratis. Adaugă frozen=True dacă vrei imutabilitate. Clasa de mai sus înlocuiește vreo 20 de linii de boilerplate.
Dacă încă scrii clase cu nimic altceva decât self.x = x în __init__, oprește-te și folosește un dataclass. Tu din viitor îți va mulțumi.
Operatorul walrus := (3.8+)
Atribuie o valoare și folosește-o în aceeași expresie. Sună banal, dar elimină un tip specific de duplicare enervantă:
# Înainte: calculezi, apoi verifici
line = f.readline()
while line:
process(line)
line = f.readline()
# După: atribuie și verifică într-un singur pas
while (line := f.readline()):
process(line)
Excelent și în list comprehensions cu apeluri costisitoare:
results = [
clean
for raw in data
if (clean := expensive_transform(raw)) is not None
]
Nu-l folosi excesiv. Dacă expresia e deja simplă, := doar adaugă zgomot. Dar când previne apelarea aceleiași funcții de două ori, e perfect.
Debugging cu f-string-uri (3.8+)
Adaugă = după o expresie într-un f-string și Python afișează atât expresia cât și valoarea ei:
x = 42
print(f"{x = }") # afișează: x = 42
print(f"{x * 2 = }") # afișează: x * 2 = 84
print(f"{len(data) = }") # afișează: len(data) = 1500
Obișnuiam să scriu print(f"x: {x}") peste tot. Trucul cu = e mai rapid, mai puțin predispus la erori și se auto-documentează. N-o să te mai întorci la metoda veche.
Instrucțiunile match (3.10+)
Versiunea Python de pattern matching. Dacă ai folosit match în Rust sau Scala, o să-ți fie familiar (deși mai puțin puternic). Dacă ai tot înlănțuit blocuri if/elif, acesta e upgrade-ul:
match command.split():
case ["quit"]:
exit_game()
case ["move", direction]:
player.move(direction)
case ["pick", "up", item]:
player.pick_up(item)
case _:
print("Unknown command")
Puterea reală e potrivirea structurală — poți destructura dicționare, obiecte și structuri imbricate:
match event:
case {"type": "click", "x": x, "y": y}:
handle_click(x, y)
case {"type": "scroll", "delta": d} if d > 0:
scroll_up(d)
case {"type": "scroll", "delta": d}:
scroll_down(abs(d))
E strict necesar? Nu. if/elif tot merge. Dar match face logica complexă de dispatch lizibilă, iar lizibilitatea e tot jocul.
Type hints care chiar ajută (3.9+)
Nu mai ai nevoie de from typing import List, Dict, Optional. Genericele built-in funcționează direct:
# Metoda veche
from typing import List, Dict, Optional
def process(items: List[Dict[str, Optional[int]]]) -> None: ...
# Metoda modernă (3.9+)
def process(items: list[dict[str, int | None]]) -> None: ...
Sintaxa X | Y pentru union types (3.10+) elimină Optional și Union dintr-o lovitură. Combină cu mypy sau pyright și prinzi bug-uri înainte să ajungă în producție. Nu la runtime — Python nu impune tipurile la runtime — dar în editor și în pipeline-ul CI.
Fuzionarea dicționarelor cu dict | dict (3.9+)
defaults = {"color": "blue", "size": "medium"}
overrides = {"size": "large", "shape": "circle"}
merged = defaults | overrides
# {'color': 'blue', 'size': 'large', 'shape': 'circle'}
Gata cu {**a, **b}. Operatorul | e mai curat și poți folosi |= pentru fuzionare in-place. Lucru mic, dar apare constant în gestionarea configurărilor.
itertools.batched() (3.12+)
De câte ori ai scris un loop ca să împarți o listă în grupuri de N? Prea multe. Acum e built-in:
from itertools import batched
list(batched("ABCDEFG", 3))
# [('A', 'B', 'C'), ('D', 'E', 'F'), ('G',)]
Dacă ești blocat pe un Python mai vechi, more-itertools are chunked() care face același lucru.
Tiparul
Majoritatea acestor funcționalități au un lucru în comun: reduc boilerplate-ul. Python a fost mereu bun la a exprima ce vrei în mai puține linii, iar fiecare versiune nouă duce asta mai departe. Costul de a nu ține pasul nu e că ți se strică codul — e că scrii mai mult cod decât trebuie, iar mai mult cod înseamnă mai multe bug-uri.
Alege o funcționalitate din lista asta pe care n-ai folosit-o încă, încerc-o în următorul PR și urmărește cât de repede devine obicei.