Wyjaśnienie rozróżnienia między zmiennymi klasy a zmiennymi instancji.
Zmienne są zasadniczo symbolami, które stoją za wartością, której używamy w programie. Programowanie zorientowane obiektowo pozwala na używanie zmiennych na poziomie klasy lub na poziomie instancji. Celem tego artykułu jest jasne rozróżnienie typów zmiennych oferowanych przez model obiektowy Pythona i dalsze omówienie osobliwego zachowania, które może prowadzić do zaskakujących rezultatów, jeśli zostanie zaniedbane. Więc zagłębmy się w to!
Jak na model obiektowy Pythona, istnieją dwa rodzaje atrybutów danych na obiektach Pythona: zmienne klasowe i zmienne instancji.
Zmienne klasowe – Deklarowane wewnątrz definicji klasy (ale poza jakimikolwiek metodami instancji). Nie są one związane z żadnym konkretnym obiektem klasy, a więc są współdzielone przez wszystkie obiekty klasy. Modyfikacja zmiennej klasowej wpływa na wszystkie obiekty instancji w tym samym czasie.
Zmienna instancji – Deklarowane wewnątrz metody konstruktora klasy (metoda __init__
). Są one związane z konkretną instancją obiektu klasy, stąd zawartość zmiennej instancyjnej jest całkowicie niezależna od jednej instancji obiektu do drugiej.
Zacznijmy od krótkiego i łatwego do strawienia przykładu:
class Car:
wheels = 4 # <- Class variable def __init__(self, name):
self.name = name # <- Instance variable
Powyżej zdefiniowana jest podstawowa, bezproblemowa klasa Car. Każda jej instancja będzie miała zmienną klasową wheels wraz z nazwą zmiennej instancji. Zainicjujmy klasę, aby uzyskać dostęp do zmiennych.
>>> jag = Car('jaguar')
>>> fer = Car('ferrari')>>> jag.name, fer.name
('jaguar', 'ferrari')>>> jag.wheels, fer.wheels
(4, 4)>>> Car.wheels
4
Dostęp do nazwy zmiennej instancji jest dość prosty. Jednakże jest trochę więcej elastyczności jeśli chodzi o dostęp do zmiennych klasowych. Podobnie jak powyżej, możemy uzyskać dostęp do kół poprzez instancję obiektu lub samą klasę.
Próbując uzyskać dostęp do nazwy poprzez klasę, spowoduje to błąd AttributeError, ponieważ zmienne instancji są specyficzne dla obiektu i są tworzone, gdy __init__
wywoływany jest konstruktor. To jest centralne rozróżnienie między klasą a zmiennymi instancji.
>>> Car.name
AttributeError: type object 'Car' has no attribute 'name'
Teraz załóżmy na razie, że nasz samochód Jaguar ma 3 koła. (tak, to głupie, ale wytrzymaj z tym!!! 😅). Aby reprezentować to w naszym kodzie, możemy zmodyfikować zmienną wheels.
>>> Car.wheels = 3
To co zrobiliśmy powyżej sprawi, że wszystkie samochody będą miały 3 koła, ponieważ zmodyfikowaliśmy zmienną klasową, która będzie miała zastosowanie do wszystkich instancji klasy Car.
>>> jag.wheels, fer.wheels
(3, 3)
Więc modyfikacja zmiennej klasowej w przestrzeni nazw klasy wpływa na wszystkie instancje tej klasy. Cofnijmy zmianę i zmodyfikujmy zmienną koła za pomocą obiektu jag.
>>> Car.wheels = 4
>>> jag.wheels = 3
To da nam pożądany rezultat.
>>> jag.wheels, fer.wheels, Car.wheels
(3, 4, 4)
Chociaż otrzymaliśmy wynik, który chcieliśmy, ale to, co stało się za kulisami, to nowa zmienna koła, która została dodana do obiektu jag i ta nowa zmienna cieniuje zmienną klasy o tej samej nazwie, nadpisując ją i ukrywając. Możemy uzyskać dostęp do obu zmiennych kół jak poniżej.
>>> jag.wheels, jag.__class__.wheels
(3, 4)
Stąd możemy wywnioskować, że jag.wheels = 3
utworzył nową zmienną instancji o tej samej nazwie co zmienna klasy (koła). Jest to ważna koncepcja, z której warto zdawać sobie sprawę.
Używanie zmiennych specyficznych dla klas i instancji może zapewnić, że nasz kod przestrzega zasady DRY, aby zredukować powtórzenia w kodzie.
Wiedząc to czuję, że może być naprawdę przydatne i zaoszczędzić wiele godzin debugowania jeden dzień. 😇
Refer to my this post to further read on various kind of methods (instance, class & static) in Python.
Wnioski
- Zmienne klasowe są współdzielone przez wszystkie obiekty, podczas gdy zmienne instancji są dla danych unikalnych dla każdej instancji.
- Zmienna instancji nadpisuje zmienne klasowe o tej samej nazwie, co może przypadkowo wprowadzić błędy lub zaskakujące zachowanie w naszym kodzie.
.