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.

Przykład. Tworzenie instacji klasy 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'}
  1. Utworzyliśmy instancję klasy FileInfo (zdefiniowaną w module fileinfo) i przypisaliśmy właśnie utworzony obiekt do zmiennej f. Skorzystaliśmy z parametru "/music/_singles/kairo.mp3", a który będzie odpowiadał argumentowi filename w metodzie __init__ klasy FileInfo.
  2. 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 jak getName, 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__.
  3. 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ą.
  4. Pamiętamy, że metoda __init__ przypisuje argument filename do self["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).

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.

Przykład. Próba zaimplementowania wycieku pamięci
>>> def leakmem():
...     f = fileinfo.FileInfo('/music/_singles/kairo.mp3')  #(1)
...
>>> for i in range(100):
...     leakmem()                                           #(2)
  1. Za każdym razem, gdy funkcja leakmem jest wywoływana, zostaje utworzona instancja klasy FileInfo, a ta zostaje przypisana do zmiennej f, 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 zmienna f wychodzi poza swój zasięg. W tym miejscu nie ma więcej żadnych referencji do nowej instancji FileInfo, ponieważ nigdzie nie przypisywaliśmy jej do czegoś innego niż f, tak więc Python zniszczy instancję za nas.
  2. 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 funkcji leakmem.

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


Przypisy

edytuj
  1. ang. double linked list