Zanurkuj w Pythonie/Definiowanie klas
Definiowanie klas
[edytuj]Python jest całkowicie zorientowany obiektowo: możemy definiować własne klasy, dziedziczyć z własnych lub wbudowanych klas, a także tworzyć instancje zdefiniowanych przez siebie klas.
Tworzenie klas w Pythonie jest proste. Podobnie jak z funkcjami, nie używamy oddzielnego interfejsu definicji. Po prostu definiujemy klasę i zaczynamy ją implementować. Klasa w Pythonie rozpoczyna się słowem kluczowym class, po którym następuje nazwa klasy, a następnie w nawiasach okrągłych umieszczamy, z jakich klas dziedziczymy.
class Nicosc(object): #(1)
pass #(2) (3)
- Nazwa tej klasy to
Nicosc, a klasa ta dziedziczy z wbudowanej klasyobject. Nazwy klas są zazwyczaj pisane przy użyciu wielkich liter np.KazdeSlowoOddzieloneWielkaLitera, ale to kwestia konwencji nazewnictwa; nie jest to wymagane. - Klasa ta nie definiuje żadnych metod i atrybutów, ale żeby kod był zgodny ze składnią Pythona, musimy coś umieścić w definicji, tak więc użyliśmy
pass. Jest to zastrzeżone przez Pythona słowo, które mówi interpreterowi "przejdź dalej, nic tu nie ma". Instrukcja ta nie wykonuje żadnej operacji i powinniśmy stosować ją, gdy chcemy zostawić funkcję lub klasę pustą. - Prawdopodobnie zauważyliśmy już, że elementy w klasie są wyszczególnione za pomocą wcięć, podobnie jak kod funkcji, instrukcji warunkowych, pętli itp. Pierwsza niewcięta instrukcja nie będzie należała już do klasy.
Uwaga!
|
Instrukcja pass w Pythonie jest analogiczna do pustego zbioru nawiasów klamrowych ({}) w Javie lub w języku C++.
|
W prawdziwym świecie większość klas definiuje własne metody i atrybuty. Jednak, jak można zobaczyć wyżej, definicja klasy, oprócz swojej nazwy z dodatkiem object w nawiasach, nie musi nic zawierać. Programiści C++ mogą zauważyć, że w Pythonie klasy nie mają wyraźnie sprecyzowanych konstruktorów i destruktorów. Pythonowe klasy mają coś, co przypomina konstruktor -- metodę __init__.
FileInfo
class FileInfo(dict): #(1)
- Jak już wiemy, klasy, z których chcemy dziedziczyć wyszczególniamy w nawiasach okrągłych, które z kolei umieszczamy bezpośrednio po nazwie naszej klasy. Tak więc klasa
FileInfodziedziczy z wbudowanej klasydict, a ta klasa, to po prostu klasa słownika.
W Pythonie klasę, z której dziedziczymy, wyszczególniamy w nawiasach okrągłych, umieszczonych bezpośrednio po nazwie naszej klasy. Python nie posiada specjalnego słowa kluczowego jak np. extends w Javie.
|
Python obsługuje dziedziczenie wielokrotne. Wystarczy w nawiasach okrągłych, umiejscowionych zaraz po nazwie klasy, wstawić nazwy klas, z których chcemy dziedziczyć i oddzielić je przecinkami np. class klasa(klasa1,klasa2).
Inicjalizowanie i implementowanie klasy
[edytuj]Ten przykład przedstawia inicjalizację klasy FileInfo za pomocą metody __init__.
class FileInfo(dict):
u"przechowuje metadane pliku" #(1)
def __init__(self, filename=None): #(2) (3) (4)
- Klasy mogą (a nawet powinny) posiadać także notkę dokumentacyjną, podobnie jak moduły i funkcje.
- Metoda
__init__jest wywoływana bezpośrednio po utworzeniu instancji klasy. Może kusić, aby nazwać ją konstruktorem klasy, co jednak nie jest prawdą. Metoda__init__wygląda podobnie do konstruktora (z reguły__init__jest pierwszą metodą definiowaną dla klasy), działa podobnie (jest pierwszym fragmentem kodu wykonywanego w nowo utworzonej instancji klasy), a nawet podobnie brzmi (słowo "init" sugeruje, że jest to konstruktor). Niestety nie jest to prawda, ponieważ obiekt jest już utworzony przed wywołaniem metody__init__, a my już otrzymujemy poprawną referencję do świeżo utworzonego obiektu. Jednak__init__w Pythonie, jest tym co najbardziej przypomina konstruktor, a ponadto pełni prawie taką samą rolę. - Pierwszym argumentem każdej metody znajdującej się w klasie, włączając w to
__init__, jest zawsze referencja do bieżącej instancji naszej klasy. Według powszechnej konwencji, argument ten jest zawsze nazywanyself. W metodzie__init__selfodwołuje się do właśnie utworzonego obiektu; w innych metodach klasy,selfodwołuje się do instancji, z której wywołaliśmy daną metodę. Mimo, że musimy wyraźnie określić argumentselfpodczas definiowania metody, nie musimy go podawać w czasie wywoływania metody; Python dodaje go automatycznie. - Metoda
__init__może posiadać dowolną liczbę argumentów i podobnie jak w funkcjach, argumenty mogą być zdefiniowane z domyślnymi wartościami (w ten sposób stają się argumentami opcjonalnymi). W tym przypadku argumentfilenamema domyślną wartość określoną jakoNone, który jest Pythonową pustą wartością.
Według konwencji, pierwszy argument metody należącej do pewnej klasy (referencja do bieżącej instancji klasy) jest nazywany self. Argument ten pełni tą samą rolę, co zastrzeżone słowo this w C++ czy Javie, ale self nie jest zastrzeżonym słowem w Pythonie, jest jedynie konwencją nazewnictwa. Niemniej lepiej pozostać przy tej konwencji, ponieważ jest to wręcz bardzo silna umowa.
|
FileInfo
class FileInfo(dict):
u"przechowuje metadane pliku"
def __init__(self, filename=None):
dict.__init__(self) #(1)
self["plik"] = filename #(2)
#(3)
- Niektóre języki pseudo-zorientowane obiektowo jak Powerbuilder posiadają koncepcję "rozszerzania" konstruktorów i innych zdarzeń, w których metoda należąca do nadklasy jest wykonywana automatycznie przed metodą podklasy. Python takiego czegoś nie wykonuje; zawsze należy wyraźnie wywołać odpowiednią metodę należącą do przodka klasy.
- Klasa ta działa podobnie jak słownik (w końcu z niego dziedziczymy), co mogliśmy zauważyć po spojrzeniu na tę linię. Przypisaliśmy argument
filenamejako wartość klucza"plik"w naszym obiekcie. - Zauważmy, że metoda
__init__nigdy nie zwraca żadnej wartości.
Kiedy używać self, a także __init__
[edytuj]Podczas definiowania metody pewnej klasy, musimy wyraźnie wstawić self jako pierwszy argument każdej metody, włączając w to __init__. Kiedy wywołujemy metodę z klasy nadrzędnej, musimy dołączyć argument self, ale jeśli wywołujemy metodę z zewnątrz, nie określamy argumentu self, po prostu go pomijamy. Python automatycznie wstawi odpowiednią referencję za nas. Na początku może się to wydawać trochę namieszane, jednak wynika to z pewnych różnic, o których jeszcze nie wiemy[1].
Metoda __init__ jest opcjonalna, ale jeśli ją definiujemy, musimy pamiętać o wywołaniu metody __init__, która należy do przodka klasy. W szczególności, jeśli potomek chce poszerzyć pewne zachowanie przodka, dana metoda podklasy musi w odpowiednim miejscu bezpośrednio wywoływać metodę należącą do klasy nadrzędnej, oczywiście z odpowiednimi argumentami.
|
Przypisy
- ↑ Wynika to z różnic pomiędzy metodami instancji klasy (ang. bound method), a metodami samej klasy (ang. unbound method)