Wektory w Pythonie (klasy i obiekty)

Klasy i Wektory

Struktura programu w Pythonie

Program w Pythonie w przeciwieństwie do C++ (i generalnie języków kompilowanych) nie składa się ze zbioru definicji (klas, funkcji, zmiennych) oraz jednego punktu startowego (funkcja main). Cały program jest serią instrukcji wykonywanych w kolejności takiej, jak w pliku.

Czy w takim razie nie ma funkcji? Popatrzmy jak wygląda instrukcja if:

if moja_zmienna <= 10:
    print("Za mało")
else:
    print("Wystarczy")

Wykonanie konstrukcji if ... else ... wcale nie powoduje wykonania całego kodu, który tam jest napisany - wykonane zostanie tylko jedno print zależenie od wartości zmiennej moja_zmienna. Podobnie definicja funkcji:

def nazwa_funkcji(argument1, argument2):
    print("Wykonuję nazwa_funkcji")
    print(f"  argument1={argument1}")
    print(f"  argument1={argument2}")
    print("  wykonano!")

Nie powoduje wykonania wszystkich wymienionych instrukcji, ale przypisania ich do podanej nazwy, czyli właściwie utworzenia zmiennej nazwa_funkcji, której wartością są instrukcje do wykonania.

Ważne

W Pythonie (prawie) wszystko jest zmienną.

Nie wierzysz? Sprawdź:

old_print = print
def lol_print(*args, *kwargs):
    old_print(*args, **args)
    old_print("LOL!")
print = lol_print
print("Hello, world!")

Jest tylko niewielki zbiór słów, których nie można użyć do nazywania zmiennych, które zawsze będą miały swoje specjalne znaczenie, np.: if, elif (odpowiednik else if), else, def, class, while, for, import.

Mimo wszystko programy w Pythonie wyglądają podobnie do programów w innych językach:

  1. Dołączając do programu biblioteki (polecenie import).

  2. Definiując własne klasy…

  3. …i własne funkcje.

  4. Pisząc kod używający tych bibliotek, klas i funkcji.

import lib1

class Klasa1:
    def metoda1(self, ):
        ...

    def metoda2(self, arg1, arg2):
        ...


print("Hello!")


class Klasa2:
    def metoda1(self, arg1):
        ...

def funkcja1(arg1, arg2):
    ...

print("I'm here")
funkcja1()
print("Bye")

Ważne

Do grupowania instrukcji w Pythonie służą wcięcia (spacje na początku linijek). Nie ma on zatem wąsatych nawiasów ({}; to odpowiednik z C++), ani begin ... end (to odpowiednik z Pascala).

Instrukcje wchodzące w skład funkcji funkcja1 są „wypisane pod tą funkcją`; podobnie funkcje wewnątrz klas i instrukjce w ich skład wchodzące.

Ilustracja wcięć do definiowania struktury programu

C++ a Python

Z grubsza równoważne programy w C++ i Pythonie:

Python vs CPP próbka kodu

Co?

C++

Python

Grupowanie instrukcji

klamry - { ... }

: i wcięcia

Oddzielanie instrukcji

; średnik

koniec linijki

Tworzenie zmiennych

Typ zmienna = wartość

zmienna = wartość

Wypisywanie

std::cout << "Napis1 " << zmmienna1 << " napis2 " << zmienna2 << ... << std::endl

print(f"Napis1 {zmienna1} napis2 {zmienna2} ...")

Dołączenie biblioteki

#include <biblioteka>

import biblioteka

Rozszerzalne tablice:

…tworzenie

std::vector<Typ> wektor

lista = []

…rozszerzanie

wektor.push_back(rzecz)

lista.append(rzecz)

…czytanie wartości

wektor[indeks]

lista[indeks]

Własne Typy

Tworzenie

class Nazwa {...}; albo struct Nazwa {...}

class Nazwa: ...

Dostęp do zmiennych innego obiektu

obiekt.zmienna

obiekt.zmienna

Dostęp do zmiennych wewnątrz obiektu

zmienna albo this->zmienna

self.zmienna (self to pierwszy argument funkcji w obiekcie)

Warunki

if (warunek) {

if warunek:

  ...

  ...

} else if (warunek) {

elif warunek:

  ...

  ...

} else {

else:

  ...

  ...

}

Pętla while

while (warunek) {

while warunek:

  ...

  ...

}

Funkcje

…tworzenie

TypWyniku nazwa(TypArg1 arg1, TypArg2 arg2, ...) { ... }

def nazwa(arg1, arg2)

…zwracanie wyniku

return wynik

return wynik

Pierwszy program o wektorach

Wyszukaj i otwórz program Kate. Utwórz nowy plik i wklej do niego następującą zawartość:

class Vector2D:
    def __init__(self, name):
        # To jest komentarz. Możesz w dowolym miejscu wstawić linijkę zaczynającą się od #
        # i napisać tak cokolwiek.
        # To dobry sposób na robienie notatek!
        self.x = 0.0
        self.y = 0.0
        self.name = name

    def add(self, other_vector):
        self.x = self.x + other_vector.x
        self.y = self.y + other_vector.x

    def multiply(self, scale):
        ...

    def show(self):
        print(f"Wektor {self.name}=({self.x}, {self.y})")

def XY(x, y):
    new_vec = Vector2D("v")
    new_vec.x = x
    new_vec.y = y
    return new_vec

print("Nowy wektor:")
v = Vector2D("v")
v.show()

print("Ustawmy kilka współrzędnych:")
v.x = 1.0
v.y = 1.2
v.show()

print("Przeskalujemy?")
v.multiply(10)
v.show()
v.multiply(1/10)
v.show()

Następnie zapisz plik jako vectors.py, zwróć uwagę na to, w jakim folderze go zapisujesz. Teraz otwórz eksplorator plików i znajdź, coś zapisał.

Następnie otwórz terminal. W terminalu, podobnie jak w eskploratorze plików chodzimy po folderach. Nie tyle w celu otwierania plików, co dla uruchamiania programów. Służą do tego polecenia:

  • cd "nazwa folderu": w ten sposób wchodzimy do folderu (odpowiednik podwójnego kliknięcia).

  • ls: w ten sposób wypisujemy listę plików w folderze, w którym jesteśmy (to, co w eksploratorze normalnie po prostu widać).

  • python "nazwa pliku.py": w ten sposób uruchamiamy program w Pythonie.

Ważne

Po każdym poleceniu należy wcisnąć klawisz Enter, żeby je wykonać. Nie musisz pisać całej nazwy pliku/folderu ręcznie, możesz wpisać początek i nacisnąć Tab — terminal uzupełni resztę.

Interaktywny Python i moduły

Pythona można używać nie tylko do wykonania instrukcji zapisanych w pliku. Można też uruchomić go tak, żeby po każdej instrukcji od razu ją wykonywał i podawał efekt wykonania.

Moduły

Python potrafi też wykonywać bardziej skomplikowane działania matematyczne. Moduł (biblioteka/nagłówek) służący do tego celu to math. Żeby móc skorzystać z nich, musimy kazać Pythonowi wczytać go do naszego programu: import math. Następnie możemy używać różnych funkcji z niego — pełna lista funkcji jest tutaj.

Możemy korzystać nie tylko z własnych Pythonowych modułów, ale także z naszych własnych. Na przykład wydaj kolejno te polecenia:

  • import vectors

  • vv = vectors.Vector2D("vv")

  • vv.show()

Wynik funkcji vs print()

Jaka jest różnica pomiędzy tymi dwiema funkcjami?

import math

def num_digits_1(n):
    return math.ceil(math.log(n))

def num_digits_2(n):
    print(math.ceil(math.log(n)))

Iloczyn skalarny

Z wykładu wiemy, że iloczyn skalarny spełnia \(v_1 \dot v_2 = 0 \;\Leftrightarrow\; v_1 \perp v_2\). Ta własność to szczególny przypadek bardziej ogólnej, mówiącej że \(v_1 \bullet v_2 = |v_1| \cdot |v_2| \cdot \cos \alpha\), gdzie \(\alpha\) to kąt między wektorami \(v_1, v_2\), zapis \(|v|\) oznacza długość wektora \(v\).

Ta własność jest całkiem przydatna w programowaniu gier!

Podsumowanie i zadania domowe

Ściąga z while/class/def/list wygenerowana przez Gemini

Interpretacja:

  • Funkcje to maszynki, do których wrzucamy argumenty, a one wypluwają jakiś wynik (return).

  • Klasy to takie większe maszynki, które trzymają w środku własne rzeczy (dane) i mogą robić z nimi różne rzeczy (funkcje w tych klasach).

  • Pętle while robią w kółko te same instrukcje, przy czym przed każdym wykonaniem od nowa sprawdzają, czy warunek jest spełniony.

  • Listy to ponumerowane od zera pudełka na dane.

Zadania domowe

Wszystkie zadania powinny być kompatybilne z klasą Vector2D napisaną na ćwiczeniach.