.. _obiekty: Wprowadzenie do obiektów -------------------------------------- Dotychczas konstruowaliście swoje programy jako jeden ciąg instrukcji, które wykonywane były w tej takiej kolejności, jak zostały napisane. Czasem deklarowaliście też funkcje. Python oferuje również inny sposób tworzenia programów : programowanie obiektowe. Chcąc nie chcąc - musicie korzystać z obiektów. W Pythonie spotykamy je na każdym kroku. Obiektem jest lista, słownik, wyrażenie regularne, a także otwary plik. Ten wykład pokaże Wam, jak deklarować własne obiekty i pomoże zrozumieć jak one działają. .. admonition:: Czym jest obiekt? :class: def *Obiekt to struktura, która zawiera w sobie dane (zmienne) oraz funkcje* Obiekt może zawierać też struktury danych (listy, słowniki, tuple) a także inne obiekty. Nowy styl programowania (czyli obiektowy) wiąże się też z nowym nazewnictwem: zmienne obiektu nazywamy jego **polami**; jego funkcje zaś - **metodami**. Do tych składowych obiektu odwołujemy się pisząc nazwę obiektu, kropkę, a po niej - nazwę pola lub metody. Ze sposobem tym spotkaliście się już, np. korzystając z list. Spis pól i metod, dostępnych w danym obiekcie, możemy znaleźć w jego dokumentacji. Klasa - deklarowanie obiektu """""""""""""""""""""""""""" Zanim zagłębimy się w klasy, powróćmy jeszcze na moment do :ref:`tego rozdziału`) wykładu o funkcjach. Znajdujący się tam przykład definiuje funkcję ``funkcja_kwadratowa()``, którą można potem użyć i to więcej niż raz. Jeżeli jednak zakomentujesz 6 linię tego kodu, program nic nie zrobi. Zadeklarowanie funkcji to co innego niż jej użycie. .. _deklarowanie_klas: Oto przykład, w którym deklarujemy klasę obiektów. Klasa nazywa się Vec3 i opisuje obiekty będące wektorami w przestrzeni 3D. W liniach 3-22 deklarujemy klasę, a potem w 24-25 tworzymy obiekty tej klasy. Podobnie jak z funkcjami - klasę deklarujemy raz, a możemy stworzyć wiele takich obiektów. Na koniec, w linii 26 wywołujemy metodę ``length()``, w linii 27 - metodę ``add()`` a w linii 29 - odczytujemy wartości pól obiektu ``v1``. .. raw:: html
Powyższy przykład, choć bardzo krótki i zapewnie niekompletny, pokazuje kilka ważnych kwestii związanych z tworzeniem obiektów: - każdy obiekt działa na swoich danych; dla przykładu jest tylko jedna metoda length(), a wyniki jej wywołania w linii różne 15 są różne - każda klasa może mieć *specjalną metodę* ``__init__()``, zwaną **konstruktorem klasy**; konstruktor tworzy pola w klasie i ewentualnie nadaje im wartości - jedynym sposobem na stworzenie pól w obiekcie, jest zainicjowanie ich w konstruktorze; klasa ``Vec3`` ma zatem trzy pola: ``x``, ``y`` i ``z`` - każda metoda klasy musi mieć co najmniej jeden argument, który jest *referencją* do obiektu *'samego siebie'*; przy wywoływaniu metody w klasie nie wykorzystujemy go; dla przykładu - metoda ``add()`` ma dwa argumenty: ``self`` i ``another_vector``, ale wywołując ją, podajemy tylko jeden argument - wektor będący drugim składnikiem dodawania - zmienna ``self`` jest potrzeba metodzie, aby mogła dostać się do *swoich danych*, czyli pól tego obiektu, na którym pracuje - obiekty Tworzymy, pisząc nazwę klasy tak, jakby była funkcją - dodajemy argumenty w nawiasach .. _str: **Metody specjalne** W klasach w języku Python można zdefiniować pewne specjalne metody (*ang. magic methods*), które mają szczególne znaczenie. Jedną z nich już poznaliście - metoda ``__init__()``, która służy do stworzenia obiektu. Kolejna to metoda ``__str__()``, która musi zwracać napis (zmienną typu *string*). Metoda ta będzie wykorzystana za każdym razem, kiedy użytkownik wywoła funkcję ``print()`` aby wydrukować obiekt. Poniżej znajduje się zmodyfikowany przykład klasy ``Vec3``, do której dodałem metodę ``__str__()``. Teraz już można napisać ``print(v1)`` a na ekranie pokażą się współrzędne: .. raw:: html
Zauważ, że zarówno metoda ``__str__()`` nie jest jawnie wywoływana, podobnie jak nie wywoływaliśmy ``__init__()``. .. admonition:: Praca domowa :class: def Dopisz do powyższej klasy metodę ``sub(another_vector)``, która będzie odejmowała ``another_vector`` od danego obiektu. Jej działanie będzie zatem bardzo podobne do ``add(another_vector)``, która dodaje. Następnie w programie zadeklaruj 3 wektory: :math:`v_1 = (1,2,0)`, :math:`v_2 = (0,2,3)` oraz :math:`v_3 = (2,2,1)` i wydrukuj wartość wyrażenia: .. math:: \frac{(v_1 - v_2) * (v_1 + v_3)}{|v_1|} gdzie :math:`|v_1|` oznacza długość wektora :math:`v_1`. a :math:`*` - iloczyn skalarny (*dot product*). Poprawny wynik: 0.0. Podpowiedź: najwygodniej Ci będzie, kiedy stworzysz dwa obiekty zawierające wektor :math:`v_1`, np ``v1a`` i ``v1b``.