Definiowanie klas przez użytkownika

Na chwilę obecną znamy już klasy takie jak: str, int, float oraz Turtle. Są one zdefiniowane w Python i dostępne do ogólnego użytku. Bardzo często zdarza się jednak że, aby rozwiązać postawiony problem potrzebne są nam nowe obiekty, związane z danymi, które odnoszą się do zagadnienia. Musimy stworzyć własne klasy danych (classes).

Jako przykład przeanalizujmy matematyczny koncept punktu. W płaszczyźnie dwuwymiarowej, punktem są dwie liczby (współrzędne), które traktowane są wspólnie jako pojedynczy obiekt. Punkty są często zapisywane w formie nawiasów, otaczających współrzędne rozdzielone przecinkiem. Np. (0, 0) reprezentuje początek układu współrzędnych, a (x, y) oznaczają punkt x jednostek w prawo i y jednostek w lewo od środka układu współrzędnych. (x,y) stanowią stan punktu (jego pola).

Nawiązując do diagramu powyżej, point możemy przedstawić w sposób poniższy:

A point has an x and a y

Typowymi operacjami, związanymi z punktami mogą być odpytanie o współrzędną x, getX lub o współrzędną y , getY. Możesz również spróbować określić odległość punktu od środka układu współrzędnych lub od innego punktu, a także wyznaczyć punkt środkowy pomiędzy dwoma punktami, jak i odpowiedzieć na pytania, czy punkt leży w środku podanego prostokąta lub okręgu. Niedługo zobaczysz, jak zorganizować te funkcjonalności wraz z danymi.

A point also has methods

Teraz, gdy znasz charakterystykę obiektu point, możesz zdefiniować nową klasę. Na początek określimy każdy punkt poprzez jego współrzędne x oraz y. Nasza pierwsza definicja klasy wygląda następująco:

1
2
3
4
5
6
7
class Point:
    """ Point class for representing and manipulating x,y coordinates. """

    def __init__(self):
        """ Create a new point at the origin """
        self.x = 0
        self.y = 0

Definicja klasy może zostać umieszczona gdziekolwiek w programie, ale z większości jest to blisko jego początku (po wyrażeniu import). Zasady składni, dotyczące definicji klasy są identyczne jak dla innych złożonych wyrażeń. Rozpoczyna się nagłówkiem w formie słowa kluczowego class, za którym znajduje się jej nazwa i zakończona symbolem dwukropka.

Jeśli pierwsza linia po nagłówku jest stringiem to interpretowana jest jako docstring tej klasy, czyli jej słowny opis wraz z komentarzem. W taki sam sposób docstringi działają w przypadku funkcji.

Każda klasa powinna zawierać metodę o szczególnej nazwie __init__. Jest to metoda inicjalizacyjna nazywana również konstruktorem. Wywoływana jest automatycznie przy każdej próbie stworzenia nowej instancji Point. Umożliwia to programiście wstępne ustawienie atrybutów instancji wartościami początkowymi. Parametr self (nazwa praktycznie przyjęta przez programistów) automatycznie staje się referencją do nowo utworzonego obiektu, który ma być poddany inicjalizacji.

Użyjmy więc nowej klasy.




(chp13_classes1)

W czasie inicjalizacji obiektów tworzymy po dwa atrybuty x oraz y i przypisujemy obu wartość 0. Uruchomienie powyższego programu nie zwróci żadnego rezultatu. W rzeczywistości utworzone zostały dwa obiekty Points, posiadające koordynaty x i y wyzerowane. Ze względu na to, że nie zlecono żadnych dodatkowych operacji na obiekcie point, nie wyświetlił się jakikolwiek wynik.

Simple object has state and methods

Możesz to sprawdzić samodzielnie poprzez codelens:

(chp13_points)

Kolejny program wzbogacony został kilkoma funkcjami print. Zauważ, że otrzymane wyniki wskazują, iż każdy Point jest rodzajem obiektu. Ponadto zwróć uwagę, że operator is zwraca False co oznacza, że mimo tego że obiekty są tych samych typów, to są od siebie różne (więcej na ten temat powiedziane zostanie w poźniejszych rozdziałach).




(chp13_classes2)

To powinno być Ci już znane – już wcześniej używaliśmy klasy do stworzenia więcej niż jednego obiektu:

from turtle import Turtle

tess = Turtle()     # Instantiate objects of type Turtle
alex = Turtle()

Zmienne p and q zostały przypisane do dwóch nowych obiektów Point. Funkcje takie jak Turtle lub Point, tworzące instancję nowego obiektu, nazywa są konstruktorami. Każdej klasie automatycznie przydzielona jest funkcja konstruktora o tej samej nazwie. Definicja tej funkcji następuje w momencie utworzenia funkcji __init__.

Pomocne może być wyobrażenie sobie klasy jako fabryki tworzącej obiekty. Klasa w samej sobie nie jest instancją punktu, ale posiada niezbędne narzędzia, aby taką instancję stworzyć. Za każdym razem przy uruchomieniu konstruktora, fabryka ta tworzy nowy obiekt. Po zjechaniu obiektu z linii produkcyjnej,uruchomiona zostaje metoda inicjalizacyjna, aby nadać domyślne ustawienia.

The combined process of „make me a new object” and „get its settings initialized to the factory default settings” is called instantiation.

Połączone procesy „utworzenia nowego obiektu” i jego inicjalizacji nosi nazwę instanizacji.

Następna część - Rozbudowanie Konstruktora