Proměnné třídy vs. proměnné instance

Vysvětlení rozdílu mezi proměnnými třídy a proměnnými instance.

Rachit Tayal
Rachit Tayal

Sledovat

9. června, 2019 – 3 minuty čtení

Proměnné jsou v podstatě symboly, které zastupují hodnotu, kterou v programu používáme. Objektově orientované programování umožňuje používat proměnné na úrovni třídy nebo instance. Cílem tohoto článku je jasné rozlišení typů proměnných, které nabízí objektový model Pythonu, a dále se zabývá zvláštním chováním, které může vést k překvapivým výsledkům, pokud se zanedbá. Pojďme se do toho tedy pustit!
Podle objektového modelu Pythonu existují dva druhy datových atributů objektů Pythonu: proměnné třídy a proměnné instance.

Proměnné třídy – Deklarované uvnitř definice třídy (ale mimo některou z metod instance). Nejsou vázány na žádný konkrétní objekt třídy, jsou tedy sdílené napříč všemi objekty třídy. Změna proměnné třídy ovlivní všechny instance objektů současně.

Proměnná instance – Deklarovaná uvnitř metody konstruktoru třídy (metoda __init__). Jsou vázány na konkrétní instanci objektu třídy, proto je obsah instanční proměnné zcela nezávislý na jednotlivých instancích objektů.

Začněme krátkým a snadno stravitelným příkladem:

class Car:
wheels = 4 # <- Class variable def __init__(self, name):
self.name = name # <- Instance variable

Výše je definována základní, nenáročná třída Car. Každá její instance bude mít proměnnou třídy kola spolu s názvem proměnné instance. Pojďme třídu instancovat, abychom měli přístup k proměnným.

>>> jag = Car('jaguar')
>>> fer = Car('ferrari')>>> jag.name, fer.name
('jaguar', 'ferrari')>>> jag.wheels, fer.wheels
(4, 4)>>> Car.wheels
4

Přístup k názvu instanční proměnné je celkem jednoduchý. Pokud však jde o přístup k proměnné třídy, je zde trochu větší flexibilita. Stejně jako výše můžeme přistupovat ke kolům prostřednictvím instance objektu nebo samotné třídy.

Také pokus o přístup ke jménu prostřednictvím třídy povede k chybě AttributeError, protože proměnné instance jsou specifické pro objekt a vytvářejí se při volání __init__konstruktoru. To je hlavní rozdíl mezi třídou a instančními proměnnými.

>>> Car.name
AttributeError: type object 'Car' has no attribute 'name'

Nyní pro tuto chvíli předpokládejme, že naše auto Jaguar má 3 kola. (ano, je to hloupost, ale vydržte to!! 😅). Abychom to v našem kódu reprezentovali, můžeme upravit proměnnou wheels.

>>> Car.wheels = 3

To, co jsme udělali výše, způsobí, že všechna auta budou mít 3 kola, protože jsme upravili proměnnou třídy, což se bude týkat všech instancí třídy Car.

>>> jag.wheels, fer.wheels
(3, 3)

Úprava proměnné třídy na jmenném prostoru třídy tedy ovlivní všechny instance třídy. Vraťme změnu zpět a upravme proměnnou wheels pomocí objektu jag.

>>> Car.wheels = 4
>>> jag.wheels = 3

Tím získáme požadovaný výsledek.

>>> jag.wheels, fer.wheels, Car.wheels
(3, 4, 4)

Sice jsme získali požadovaný výsledek, ale to, co se stalo v zákulisí, je nová proměnná wheels, která byla přidána do objektu jag, a tato nová proměnná stínuje proměnnou třídy se stejným názvem, přepisuje ji a skrývá. K oběma proměnným wheels můžeme přistupovat, jak je uvedeno níže.

>>> jag.wheels, jag.__class__.wheels
(3, 4)

Z toho můžeme usoudit, že jag.wheels = 3 vytvořil novou instanční proměnnou se stejným názvem jako proměnná třídy (wheels). To je důležitý pojem, který je třeba si uvědomit.
Používání proměnných specifických pro třídu a instanci může zajistit, že náš kód bude dodržovat princip DRY, aby se omezilo opakování v kódu.
Mám pocit, že znalost tohoto může být opravdu užitečná a ušetřit spoustu hodin ladění jednoho dne. 😇
Pro další informace o různých druzích metod (instančních, třídních & statických) v jazyce Python si přečtěte můj tento příspěvek.

Závěry

  • Proměnné třídy jsou sdílené pro všechny objekty, zatímco proměnné instance jsou určeny pro data jedinečná pro každou instanci.
  • Proměnná instance přepisuje proměnné třídy se stejným názvem, což může do našeho kódu nechtěně vnést chyby nebo překvapivé chování.

.

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna.