Zanurkuj w Pythonie/Tworzenie instancji klasy: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
zamiana ProstaNawigacja->Subst:ProstaNawigacja
Piotr (dyskusja | edycje)
mNie podano opisu zmian
Linia 1:
{{Podświetl|py}}
== Tworzenie instancji klasy ==
Tworzenie instancji klas jest dosyć proste. W tym celu wywołujemy klasę tak jak byjakby była funkcją, dodając odpowiednie argumenty, które są określone w metodzie <ttcode>__init__</ttcode>. Zwracaną wartością będzie zawsze nowo utworzony obiekt.
 
'''{{Python/Przykład
|5.7. |Tworzenie instacji klasy <code>FileInfo'''</code>
|tekst=
>>> import fileinfo
>>> f = fileinfo.FileInfo("/music/_singles/kairo.mp3") #(1)
>>> f.__class__ #(2)
{{samp|<class fileinfo.FileInfo at 010EC204>}}
>>> f.__doc__ #(3)
{{samp|'store file metadata'}}
>>> f #(4)
{{samp|{'name': '/music/_singles/kairo.mp3'}}}
 
# Utworzyliśmy instancję klasy <code>FileInfo</code> (zdefiniowaną w module <ttcode>fileinfo</ttcode>) i przypisaliśmy właśnie utworzony obiekt do zmiennej <ttcode>f</ttcode>. UżyliśmySkorzystaliśmy jednegoz parametru <ttcode>"/music/_singles/kairo.mp3"</ttcode>, a który będzie odpowiadał argumentowi <ttcode>filename</ttcode> w metodzie <ttcode>__init__</ttcode> klasy <code>FileInfo</code>.
# Każda instancja pewnej klasy ma wbudowany atrybut <ttcode>__class__</ttcode>, który jest klasą danego obiektu. (Dodajmy, że ta reprezentacja dołącza fizyczny adres instancji na moim komputerze, ale na twoim reprezentacja będzie się nieco różniła). Programiści Javy mogą być zaznajomieni z klasą <ttcode>Class</ttcode>, która posiada metody takie jak <ttcode>getName</ttcode>, czy też <ttcode>getSuperclass</ttcode>, aby pobrać metadane o pewnym obiekcie. W Pythonie, ten rodzaj metadadanych, jest dostępny bezpośrednio z obiektu wykorzystując atrybuty takie jak <ttcode>__class__</ttcode>, <ttcode>__name__</ttcode>, czy <ttcode>__bases__</ttcode>.
# MożeszMoż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 [[../Definiowanie klas|<ttcode>__init__</ttcode> przypisuje argument <ttcode>filename</ttcode> do <code>self["name"]</code>]]? WTo dobrze, w tym miejscu mamy wynikrezultat tej operacji. Argumenty podawane podczas tworzenia instancji pewnej klasy zostają wysłane do metody <ttcode>__init__</ttcode> (pozawyłączając referencjąpierwszy do obiektu (argument, który nazwaliśmy <ttcode>self</ttcode>),. Python zrobił to za nas).
}}
 
{{Infobox|
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 <ttcode>new</ttcode> w Javie czy C++.
}}
 
=== Odśmiecanie pamięci ===
Jeśli tworzenie nowej instancji jest proste, to usuwanie jej jest jeszcze prostsze. W ogólności nie musimy wyraźnie zwalniać instancji klasy, ponieważ Python robi to automatycznie, gdy wychodząwychodzi one poza swój zasięg. W Pythonie rzadko występują wycieki pamięci.
 
{{Python/Przykład
Jeśli tworzenie nowej instancji jest proste, to usuwanie jej jest jeszcze prostsze. W ogólności nie musimy wyraźnie zwalniać instancji klasy, ponieważ Python robi to automatycznie, gdy wychodzą one poza swój zasięg. W Pythonie rzadko występują wycieki pamięci.
'''Przykład |5.8. |Próba zaimplemetowaniazaimplementowania wycieku pamięci'''
|tekst=
 
>>> def leakmem():
... f = fileinfo.FileInfo('/music/_singles/kairo.mp3') #(1)
...
>>> for i in range(100):
... leakmem() #(2)
 
# Za każdym razem, gdy funkcja <ttcode>leakmem</ttcode> jest wywoływana, zostaje utworzona instancja klasy <ttcode>FileInfo</ttcode>, a ta zostaje przypisana do zmiennej <ttcode>f</ttcode>, która jest lokalną zmienną wewnątrz funkcji. WtedyFunkcja funkcjata kończy się bez jakiegokolwiek wyraźnego zwolnienia zmiennejpamięci zajmowanej przez zmienną <ttcode>f</ttcode>, a więc spodziewalibyśmy się wycieku pamięci, lecz tak nie będzie. Kiedy funkcja się kończy, lokalna zmienna <ttcode>f</ttcode> wychodzi poza swój zakres. W tym miejscu nie ma więcej żadnych referencji do nowej instancji <ttcode>FileInfo</ttcode>, ponieważ nigdzie nie przypisywaliśmy jej do czegoś innego niż <ttcode>f</ttcode>), tak więc Python zniszczy instancję za nas.
# Niezależnie od tego, jak wiele razy wywołamy funkcję <ttcode>leakmem</ttcode>, nigdy nie otrzymamy wycieku pamięci, ponieważ za każdym razem kiedy to zrobimy Python będzie niszczył nowo utworzony obiekt przed wyjściem z funkcji <ttcode>leakmem</ttcode>.
}}
 
Technicznym terminem tego sposobu odśmiecania pamięci jest „zliczanie"[[w:Reference odwołań”counting|zliczanie odwołań]]". Python przechowuje listę referencji do każdej utworzonej instancji. W powyższym przykładzie, mamy tylko jedną referencję do instancji <ttcode>FileInfo</ttcode> -- zmienną <ttcode>f</ttcode>. Kiedy funkcja się kończy, zmienna <ttcode>f</ttcode> wychodzi poza zakres, więc licznik odwołań zmiejszazmniejsza się do <ttcode>0</ttcode> i Python niszczy 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 tworzyłeś dwie instancje, które odwoływały się do siebie nawzajem (np. instancja listy dwukierunkowej (ang. ''double linked list''), 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 PythoniePythona 2.0 mamy dodatkowy sposób odśmiecania pamięci nazywany po ang. “mark[[w:Garbage collection#Mark and Sweep|''mark-and-sweep”sweep'']] (znaczoznacz i zamiataj), dzięki któremu w sprytny sposób Python odnajduje różne wirtualne blokady i poprawnie czyści referencje tworzącecykliczne cyklodwołania.
 
Podsumowując w języku tym można po prostu zapomnieć o zarządzaniu pamięcią i pozostawić tę sprawę Pythonowi.
 
<noinclude>
{{Nawigacja|Python|
[[Python../Definiowanie klas|Definiowanie klas/]]|
[[Python../Klasa opakowująca UserDict|Klasa opakowująca <ttcode>UserDict</ttcode>]]|
}}
{{Podświetl|py}}
</noinclude>