În ultimii ani, Python a evoluat dintr-un limbaj cu tipare exclusiv dinamică într-un ecosistem în care Type Hints (adnotările de tip) sunt considerate standardul de aur pentru proiectele de producție. În combinație cu un verificator static (precum mypy sau pyright) și o bibliotecă de validare la runtime ultra-rapidă (precum Pydantic v2), Python oferă aceeași siguranță ca limbajele compilate, păstrând în același timp flexibilitatea sa caracteristică.
from typing import Protocol
# Definim un Protocol structural (interfață):
# Orice clasă care implementează metoda 'salveaza()' este compatibilă automat!
class Salubilizabil(Protocol):
def salveaza(self) -> bool:
...
class ArticolBlog:
def salveaza(self) -> bool:
print("Articol salvat în baza de date.")
return True
class FisierLog:
def salveaza(self) -> bool:
print("Log salvat pe disc.")
return True
# Funcția acceptă orice obiect care respectă protocolul (fără moștenire explicită!):
def persista_date(entitate: Salubilizabil) -> None:
entitate.salveaza()
persista_date(ArticolBlog()) # Valid conform mypy!
persista_date(FisierLog()) # Valid conform mypy!
Pydantic v2: Validare la Runtime Scrisă în Rust
În timp ce type hints ajută doar la scrierea codului în IDE, Pydantic v2 validează și transformă datele concrete primite din exterior (JSON-uri de la clienți, variabile de mediu, răspunsuri de baze de date). În versiunea 2, nucleul său (pydantic-core) a fost rescris în Rust, oferind viteze de validare de 5 până la 20 de ori mai mari decât Pydantic v1.
from pydantic import BaseModel, Field, EmailStr, field_validator
from datetime import datetime
class ComandaNoua(BaseModel):
# Validări declarative pe câmpuri:
id_comanda: int = Field(gt=0, description="Identificator unic pozitiv")
email_client: EmailStr
produse_ids: list[int] = Field(min_length=1, description="Comanda trebuie să conțină minim un produs")
total_plata: float = Field(ge=0.0)
data_creare: datetime = Field(default_factory=datetime.utcnow)
# Validator personalizat pe un câmp specific:
@field_validator('email_client')
@classmethod
def normalizeaza_email(cls, v: str) -> str:
return v.lower().strip()
# Parsare și validare dintr-un dicționar brut JSON:
date_brute = {
"id_comanda": 105,
"email_client": " Ion.Popescu@Dexblog.RO ",
"produse_ids": [10, 42],
"total_plata": 349.99
}
comanda = ComandaNoua.model_validate(date_brute)
# Email-ul a fost sanitizat automat:
print(comanda.email_client) # "ion.popescu@dexblog.ro"
# Serializare ultra-rapidă înapoi în JSON:
json_output = comanda.model_dump_json()
Bune Practici de Arhitectură
- Separarea Modelelor de Domeniu de Modelele de API: Nu folosiți aceleași clase Pydantic pentru request-ul HTTP, entitatea internă de business și modelul ORM (SQLAlchemy/Tortoise). Folosiți DTO-uri dedicate pentru fiecare strat.
- Imuabilitate când este posibil: Activați
model_config = ConfigDict(frozen=True)pentru a transforma modelele în structuri imuabile rezistente la mutații accidentale în cod.