A hagyományos Python objektumok gyakran pazarlóak. A Python Data Classes használatával azonban drasztikusan csökkentheted a kód mennyiségét, miközben növeled a programod sebességét. A szabványos objektumok minden adatot egy belső szótárban tárolnak. Ez rugalmas, de nagy memóriaigénnyel jár. Ráadásul alapértelmezésben nem használhatók például szótár kulcsként sem. Ebben a cikkben hét konkrét lépésen keresztül optimalizáljuk az osztályaidat. Másold ki a kódokat és tedd hatékonyabbá a fejlesztést.
1. Fagyasztás a biztonságért
A frozen=True paraméterrel megváltoztathatatlanná (immutábilissá) teheted az objektumodat. Ez két előnnyel jár: biztonságosabb a kód, és az objektum „hash-elhetővé” válik.
Ez elengedhetetlen, ha az objektumot szótár (dictionary) kulcsként szeretnéd használni.
Íme a kód a gyorsítótárazáshoz:
from dataclasses import dataclass
@dataclass(frozen=True)
class CacheKey:
user_id: int
resource_type: str
timestamp: int
cache = {}
# Most már használhatod kulcsként az objektumot
key = CacheKey(user_id=42, resource_type="profile", timestamp=1698345600)
cache[key] = {"data": "számítási_eredmény"}
Fagyasztás nélkül TypeError hibát kapnál a kulcs hozzáadásakor. Ez a minta megakadályozza a véletlen módosításokat is a program futása során.
2. Memória optimalizálás slotokkal
Több ezer objektum létrehozásakor a memóriaigény gyorsan megnő. A hagyományos __dict__ tárolás rengeteg helyet foglal.
A slots=True paraméterrel utasítod a Pythont, hogy szótár helyett fix méretű tömböt használjon. Ez jelentős memóriamegtakarítást és gyorsabb attribútum-elérést eredményez.
from dataclasses import dataclass
@dataclass(slots=True)
class Measurement:
sensor_id: int
temperature: float
humidity: float
A kompromisszum annyi, hogy futásidőben nem adhatsz hozzá új mezőket az objektumhoz.
3. Egyenlőségvizsgálat testreszabása
Gyakran előfordul, hogy két objektumot azonosnak tekintünk, még ha a metaadataik el is térnek. Például egy felhasználó azonosítója ugyanaz, de a belépési ideje más.
A field(compare=False) beállítással kizárhatsz mezőket az összehasonlításból.
from dataclasses import dataclass, field
from datetime import datetime
@dataclass
class User:
user_id: int
email: str
# A belépési idő nem számít az egyenlőségnél
last_login: datetime = field(compare=False)
login_count: int = field(compare=False, default=0)
user1 = User(1, "alice@example.com", datetime.now(), 5)
user2 = User(1, "alice@example.com", datetime.now(), 10)
print(user1 == user2) # True lesz, mert az ID és email egyezik
Ez megakadályozza a hibás egyezésvizsgálatokat a logikailag azonos entitásoknál.
4. Mutábilis alapértelmezések kezelése
A Python egyik klasszikus hibalehetősége a változtatható alapértelmezett értékek (pl. üres lista) használata. Ha így teszel, minden példány ugyanazon a listán fog osztozni.
A Python Data Classes erre kínálja a default_factory megoldást.
from dataclasses import dataclass, field
@dataclass
class ShoppingCart:
user_id: int
# Minden példány új, üres listát kap
items: list[str] = field(default_factory=list)
metadata: dict = field(default_factory=dict)
cart1 = ShoppingCart(user_id=1)
cart2 = ShoppingCart(user_id=2)
cart1.items.append("laptop")
print(cart2.items) # Üres marad, helyesen
Ez a módszer listák, szótárak és halmazok esetén is kötelező a tiszta kódhoz.
5. Adatvalidáció és számított mezők
Az automatikusan generált __init__ metódus kényelmes, de néha ellenőrizni kell a bemenetet. Erre való a __post_init__ horog.
Ez a metódus közvetlenül az inicializálás után fut le. Használhatod mezők kiszámítására vagy hibák dobására.
from dataclasses import dataclass, field
@dataclass
class Rectangle:
width: float
height: float
# Ez a mező nem kerül be az init paraméterek közé
area: float = field(init=False)
def __post_init__(self):
self.area = self.width * self.height
if self.width <= 0 or self.height <= 0:
raise ValueError("A méreteknek pozitívnak kell lenniük!")
rect = Rectangle(5.0, 3.0)
print(rect.area) # 15.0
6. Automatikus rendezés
Szeretnéd sorba rendezni az objektumaidat külön kód írása nélkül? Az order=True paraméterrel a Python legenerálja az összehasonlító metódusokat (<, >, <=, >=).
A rendezés a mezők sorrendje alapján történik (balról jobbra).
from dataclasses import dataclass
@dataclass(order=True)
class Task:
priority: int # Ez alapján rendez először
name: str
tasks = [
Task(priority=3, name="Alacsony prioritás"),
Task(priority=1, name="Kritikus hiba"),
Task(priority=2, name="Új funkció")
]
for task in sorted(tasks):
print(f"{task.priority}: {task.name}")
Kimenet:
1: Kritikus hiba
2: Új funkció
3: Alacsony prioritás
7. Inicializáló változók (InitVar)
Néha olyan adatot kell átadnod a konstruktornak, amit nem akarsz az objektumban tárolni. Erre szolgál az InitVar.
Példánkban egy SSL kapcsolót adunk át, ami befolyásolja a kapcsolat stringet, de maga a kapcsoló nem tárolódik el.
from dataclasses import dataclass, field, InitVar
@dataclass
class DatabaseConnection:
host: str
port: int
# Csak az init fázisban létezik
ssl: InitVar[bool] = True
connection_string: str = field(init=False)
def __post_init__(self, ssl: bool):
protocol = "https" if ssl else "http"
self.connection_string = f"{protocol}://{self.host}:{self.port}"
conn = DatabaseConnection("localhost", 5432, ssl=True)
print(conn.connection_string)
print(hasattr(conn, 'ssl')) # False, nem tároltuk el
Mikor ne használd?
Bár a Python Data Classes hatékony, nem mindenre megoldás. Kerüld a használatát, ha:
- Bonyolult öröklődési hierarchiát építesz.
- Az osztályod elsősorban viselkedést (metódusokat) tartalmaz, nem adatot.
- Szigorú validációra vagy szerializációra van szükséged (ilyenkor a Pydantic jobb választás).
Az itt bemutatott technikákkal a kódod nemcsak rövidebb, de gyorsabb és megbízhatóbb is lesz.




