Zanurkuj w Pythonie/Tworzenie instancji klasy
Tworzenie instancji klasy
[edytuj]Tworzenie instancji klas jest dosyć proste. W tym celu wywołujemy klasę tak jakby była funkcją, dodając odpowiednie argumenty, które są określone w metodzie __init__
. Zwracaną wartością będzie zawsze nowo utworzony obiekt.
FileInfo
>>> import fileinfo >>> f = fileinfo.FileInfo("/music/_singles/kairo.mp3") #(1) >>> f.__class__ #(2) <class 'fileinfo.FileInfo'> >>> f.__doc__ #(3) u'przechowuje metadane pliku' >>> f #(4) {'plik': '/music/_singles/kairo.mp3'}
- Utworzyliśmy instancję klasy
FileInfo
(zdefiniowaną w modulefileinfo
) i przypisaliśmy właśnie utworzony obiekt do zmiennejf
. Skorzystaliśmy z parametru"/music/_singles/kairo.mp3"
, a który będzie odpowiadał argumentowifilename
w metodzie__init__
klasyFileInfo
. - Każda instancja pewnej klasy ma wbudowany atrybut
__class__
, który jest klasą danego obiektu. Programiści Javy mogą być zaznajomieni z klasąClass
, która posiada metody takie jakgetName
, czy teżgetSuperclass
, aby pobrać metadane o pewnym obiekcie. W Pythonie ten rodzaj metadadanych, jest dostępny bezpośrednio z obiektu wykorzystując atrybuty takie jak__class__
,__name__
, czy__bases__
. - Możemy pobrać notkę dokumentacyjną w podobny sposób, jak to czyniliśmy w przypadku funkcji czy modułu. Wszystkie instancje klasy współdzielą tę samą notkę dokumentacyjną.
- Pamiętamy, że metoda
__init__
przypisuje argumentfilename
doself["plik"]
? To dobrze, w tym miejscu mamy rezultat tej operacji. Argumenty podawane podczas tworzenia instancji pewnej klasy są wysłane do metody__init__
(wyłączając pierwszy argument,self
. Python zrobił to za nas).
W Pythonie, aby utworzyć instancję pewnej klasy, wywołujemy klasę tak, jakby to była zwykła funkcja zwracająca pewną wartość. Python nie posiada jakiegoś kluczowego słowa jakim jest np. operator new w Javie czy C++.
|
Odśmiecanie pamięci
[edytuj]Jeśli tworzenie nowej instancji jest proste, to jej usuwanie jest jeszcze prostsze. W ogólności nie musimy wyraźnie zwalniać instancji klasy, ponieważ Python robi to automatycznie, gdy wychodzi one poza swój zasięg. W Pythonie rzadko występują wycieki pamięci.
>>> def leakmem(): ... f = fileinfo.FileInfo('/music/_singles/kairo.mp3') #(1) ... >>> for i in range(100): ... leakmem() #(2)
- Za każdym razem, gdy funkcja
leakmem
jest wywoływana, zostaje utworzona instancja klasyFileInfo
, a ta zostaje przypisana do zmiennejf
, która jest lokalną zmienną wewnątrz funkcji. Funkcja ta kończy się bez jakiegokolwiek wyraźnego zwolnienia pamięci zajmowanej przez zmiennąf
, a więc spodziewalibyśmy się wycieku pamięci, lecz tak nie będzie. Kiedy funkcja się kończy, lokalna zmiennaf
wychodzi poza swój zasięg. W tym miejscu nie ma więcej żadnych referencji do nowej instancjiFileInfo
, ponieważ nigdzie nie przypisywaliśmy jej do czegoś innego niżf
, tak więc Python zniszczy instancję za nas. - Niezależnie od tego, jak wiele razy wywołamy funkcję
leakmem
, nigdy nie nastąpi wyciek pamięci, ponieważ za każdym razem kiedy to zrobimy, Python będzie niszczył nowo utworzony obiekt przed wyjściem z funkcjileakmem
.
Technicznym terminem tego sposobu odśmiecania pamięci jest "zliczanie odwołań" (zobacz w Wikipedii). Python przechowuje listę referencji do każdej utworzonej instancji. W powyższym przykładzie, mamy tylko jedną referencję do instancji FileInfo
-- zmienną f
. Kiedy funkcja się kończy, zmienna f
wychodzi poza zasięg, więc licznik odwołań zmniejsza się do 0
i Python zniszczy tę instancję automatycznie.
W poprzednich wersjach Pythona występowały sytuacje, gdy zliczanie odwołań zawodziło i Python nie mógł wyczyścić po nas pamięci. Jeśli tworzyliśmy dwie instancje, które odwoływały się do siebie nawzajem (np. instancja listy dwukierunkowej[1], w których każdy węzeł wskazuje na poprzedni i następny znajdujący się w liście), żadna instancja nie była niszczona automatycznie, ponieważ Python uważał (poprawnie), że ciągle mamy referencję do każdej instancji. Od Pythona 2.0 mamy dodatkowy sposób odśmiecania pamięci, nazywany po ang. mark-and-sweep (oznacz i zamiataj, zobacz w Wikipedii), dzięki któremu Python w sprytny sposób wykrywa różne wirtualne blokady i poprawnie czyści cykliczne odwołania.
Podsumowując, w języku tym można po prostu zapomnieć o zarządzaniu pamięcią i pozostawić tę sprawę Pythonowi.
Materiały dodatkowe
[edytuj]- Python Library Reference omawia wbudowane atrybuty podobne do
__class__
- Python Library Reference dokumentuje moduł
gc
, który daje niskopoziomową kontrolę nad odśmiecaniem pamięci
Przypisy
[edytuj]- ↑ ang. double linked list