Zanurkuj w Pythonie/Klasa opakowująca UserDict: Różnice pomiędzy wersjami
Usunięta treść Dodana treść
Nie podano opisu zmian |
Nie podano opisu zmian |
||
Linia 2:
== Klasa opakowująca <tt>UserDict</tt> ==
Klasa <tt>FileInfo</tt> działa podobnie do słownika, o czym mogliśmy się już wcześniej przekonać. Aby ją lepiej zgłębić przyjrzyjmy się klasie <tt>UserDict</tt> w module <tt>UserDict</tt>, która jest przodkiem klasy <tt>FileInfo</tt>. Nie ma w niej nic specjalnego; jest to klasa napisana w Pythonie i przechowywana w pliku o rozszerzeniu <tt class="lang-none">.py</tt>
{{Infobox|
W <tt>
'''Przykład 5.9. Definicja klasy <tt>UserDict</tt>'''
Linia 16:
# Klasa <tt>UserDict</tt> jest klasą bazową, nie dziedziczy nic z innych klas.
# Metodę <tt>__init__</tt> nadpisaliśmy w klasie <tt>FileInfo</tt>. Zauważmy, że lista argumentów w klasie przodka jest różna niż w klasie potomka.
# Python wspiera
# metoda <tt>update</tt> jest duplikatorem słownika: kopiuje wszystkie klucze i wartości z jednego słownika do drugiego. Ta metoda nie czyści słownika docelowego; jeśli były tam już jakieś klucze, te, które są w słowniku źródłowym zostaną nadpisane ale pozostałe się nie zmienią. Myśl o <tt>update</tt> jak o funkcji łączenia, nie kopiowania.
# tej składni mogłeś wcześniej nie widzieć (nie używałem jej w przykładach z tej książki). Jest to instrukcja <tt>if</tt> ale zamiast wciętego bloku zaczynającego się w następnej linii jest tu pojedyncza instrukcja w tej samej linii, za dwukropkiem. Jest to całkowicie poprawna składnia, będąca tylko skrótem, którego możesz używać, jeśli masz tylko jedną instrukcję w bloku (tak jak pojedyncza instrukcja bez klamer w C++). Możesz użyć tej składni albo wciętego kodu w następnych liniach, ale nie możesz użyć obu składni w tym samym bloku kodu.
Linia 25:
{{Infobox|
Guido, pierwszy twórca Pythona, tak wyjaśnia zasłanianie funkcji: "Klasy pochodne mogą zasłonić metody klas bazowych. Ponieważ metody nie mają żadnych specjalnych przywilejów wołając inne metody tego samego obiektu, może okazać się, że metoda klasy bazowej wołająca inną metodę zdefiniowaną w tej samej klasie bazowej woła właściwie metodę klasy pochodnej która ją zasłania. (Dla programistów C++: wszystkie metody w Pythonie zachowują się jakby były wirtualne.)" Jeśli dla Ciebie nie ma to sensu (dla mnie osobiście jest to strasznie
{{Uwaga|
Linia 44:
# <tt>clear</tt> jest normalną metodą klasy; jest dostępna publicznie i może być wołana przez kogokolwiek w dowolnej chwili. Zauważ, że <tt>clear</tt>, jak wszystkie metody klas, ma <tt>self</tt> jako pierwszy argument. (Pamiętaj, że nie dodajesz <tt>self</tt> gdy wywołujesz metodę; Python robi to za Ciebie.) Zauważ podstawową cechę tej opakowującej klasy: przechowuje prawdziwy słownik (<tt>data</tt>) jako atrybut danych i definiuje wszystkie metody, które ma prawdziwy słownik, a w każdej z tych metod zwraca wynik identyczny do odpowiedniej metody słownika. (Gdybyś zapomniał, metoda <tt>clear</tt> słownika kasuje jego wszystkie klucze i wartości.)
# metoda <tt>copy</tt> słownika zwraca nowy słownik, będący dokładną kopią oryginału (mający takie same pary klucz-wartość). Ale klasa <tt>UserDict</tt> nie może po prostu wywołać <tt>self.data.copy</tt>, ponieważ ta metoda zwraca słownik a to co chcemy tu zrobić, to zwrócenie nowej instancji klasy takiej, jak <tt>self</tt>.
# Używamy atrybutu <tt>
# Jeśli <tt>self.__class__</tt> nie jest <tt>UserDict</tt>-em, to <tt>self</tt> musi być jakąś podklasą <tt>UserDict</tt>-a (jak być może <tt>FileInfo</tt>) <!-- in which case life gets trickier -->. <tt>UserDict</tt> nie wie, jak utworzyć dokładną kopię jednego ze swoich potomków. W tym celu możemy np. znając atrybuty zdefiniowane w podklasie, wykonać na nich iterację kopiując każdy z tych atrybutów. Na szczęście istnieje moduł, który wykonuje dokładnie to samo, nazywa się on <tt>copy</tt>. Nie będziemy się tutaj wdawać w szczegóły (choć jest to niezły (cool) moduł, jeśli wgłębisz się w niego samemu). Wystarczy wiedzieć, że <tt>copy</tt> potrafi kopiować dowolne obiekty, a tu widzimy, jak możemy z niego skorzystać.
# Pozostałe metody są bezpośrednimi przekierowaniami wywołującymi wbudowane metody na <tt>self.data</tt>.
{{Infobox|
1=W wersjach 2.2 i wcześniejszych nie można było bezpośrenio tworzyć podklas wbudowanych typów jak napisy, listy czy słowniki. Aby to zrekompensować, Python dostarcza klasy opakowujące, które naśladują zachowanie wbudowanych typów danych. Są to: <tt>UserString</tt>, <tt>UserList</tt>
}}
W Pythonie możemy dziedziczyć bezpośrednio
'''Przykład 5.11. Dziedziczenie bezpośrednio z wbudowanej klasy <tt>dict</tt>'''
Linia 63:
# Pierwsza różnica polega na tym, że nie importujemy modułu <tt>UserDict</tt>, ponieważ <tt>dict</tt> jest wbudowanym typem danych i jest ciągle dostępny. Druga polega na tym, że dziedziczymy bezpośrednio z klasy <tt>dict</tt>, zamiast z klasy <tt>UserDict.UserDict</tt>.
# Trzecia różnica jest subtelna, lecz też bardzo ważna.
<noinclude>
|