Przejdź do treści głównej

Programowanie obiektowe - własne funkcje i obiekty

Funkcje

Do tej pory korzystaliśmy z funkcji dostarczonych nam przez Pythona (np . print), lub "wgranych" z biblioteki / modułu.

Pisząc własne programy już na tym etapie zetknęliśmy się z sytuacją gdy robiliśmy podobną rzecz wiele razy - zmieniały się np. tylko dane wejściowe np. modyfikowaliśmy jakiś adres w książce adresowej, gdzie zmieniało się tylko, który adres był modyfikowany.

Możemy taką funkcjonalność ;) zebrać w całość i udostępnić jako własną funkcję.

Własną funkcję deklarujemy używając słowa def.

np.

def kwadrat(x:int) ->  int:
	wynik = x * x
	return wynik

Zwróćcie uwagę na słowo return - wykorzystujemy je jeśli chcemy, żeby nasza funkcja poza wykonaniem jakiejś operacji zwróciła nam jakąś wartość (którą np. możemy przypisać do zmiennej). Bardzo dużo funkcji korzysta z tej opcji - np. funkcja sum zwraca nam sumę dwóch liczb, funkcja max zwraca nam największą wartość przechowywaną chociażby na liście itd.

Nie jest to jednak reguła - np. funkcja print wyświetla nam daną zawartość na ekranie, ale nie zwraca żadnej wartości.

Powyższy przykład zawiera nieco nieobowiązkowych rzeczy:

  • informację o oczekiwanym typie danych parametru wykorzystywanego w funkcji (x:int)
  • informację o zwracanym typie danych (-> int)

Dodawanie tych informacji jest dobrą praktyką - ułatwia nam (i innym użytkownikom tego kodu) korzystanie z programu.

Ponadto dzięki nim narzędzia jakich używamy do pisania będą w stanie podpowiadać nam w przypadku popełnienia błędu związanego z użyciem nieprawidłowego typu.

Tak skonstruowana funkcje wykorzystujemy identycznie jak te wbudowane np.

def kwadrat(x:int) ->  int:
	wynik = x * x
	return wynik

liczba = kwadrat(2)
print(liczba)

Powyższa kod wyświetli nam 4 gdyż jest to 2 podniesione do kwadratu (a właśnie to robi ta funkcja kwadrat).

Klasy

Zazwyczaj chcemy żeby w naszym kodzie było możliwie mało powtórzeń, całość była jak najbardziej czytelna, a osoby korzystające z naszego programu miały jasne wytyczne czego nasz kod oczekuje.

Jednym z narzędzi w drodze do tego celu są klasy, będące fundamentem podejścia nazywanego programowaniem obiektowym.

Korzystając z tej metody staramy się modelować nasz kod w sposób nieco przypominający to jak zbieramy informacje o otaczającym nas świecie. Np. grupujemy gatunki w podobne kategorie. Pies domowy należy do rodziny psowatych, które z kolei należą do rzędu ssaków drapieżnych.

Mimo tego, że psy różnią się od siebie (ciężko pomylić jamnika z dobermanem) to mają one pewne cechy wspólne, które umożliwiają nam przypisanie ich do tego typu (gatunku).

Podobnie modelując aplikację staramy się znaleźć jakieś elementy wspólne obiektów, które tworzymy i na tej podstawie stworzyć typ grupujący je - służy on jako swego rodzaju szablon do stworzenia nowych obiektów.

Oprócz cech charakterystycznych (atrybutów) klasa zawiera też metody - czyli rzeczy, które dany obiekt może robić.

Jako przykład posłużmy się postacią do gry komputerowej rpg. Każda z nich będzie miała jakieś punkty życia, punkty magii, profesję itd. Żeby nie wymyślać tej struktury za każdym razem możemy zdefiniować odpowiednią klasę:

class PostacGracza:
	def __init__(self, imie, profesja):
		self.imie = imie
		self.profesja = profesja
		self.hp = 100
		self.mana = 100

gracz1 = PostacGracza("Fizban", "mag")
gracz2 = PostacGracza("Taz", "łotrzyk")

Obie stworzone postaci (gracz1 i gracz2) zostały zrobione na podstawie tego samego szablonu (klasy PostacGracza), ale nie są identyczne - różnią się imieniem i profesją. Co więcej pozostałe ich atrybuty (hp i mana) mimo, że na start mają tę samą wartość są od siebie całkowicie niezależne (są to zupełnie osobne wartości). Czyli np. jeśli w trakcie gry Fizban otrzyma 30 obrażeń to będzie miał on 70 hp, podczas gdy Taz nadal będzie miał 100.

Klasa to nie obiekt

Ważne aby zdawać sobie sprawę, że ten przygotowany "szablon" nie jest równoznaczny z obiektem danego typu. W powyższym przykładzie PostacGracza to opis klasy, a gracz1 to juz obiekt klasy PostacGracza ("szablon wypełniony zawartością).

Porównując klasy do np. szablonów ankiet, które dajemy komuś do wypełnienia to sam szablon byłby klasą, a uzupełniona, wypełniona przez kogoś ankieta byłaby obiektem.

Tworzenie klasy

Metoda __init__

  • to sekcja, która jest uruchamiana podczas tworzenia naszego obiektu na podstawie szablonu (klasy). Służy do przypisania obiektowi jego indywidualnych cech (w powyższym przykładzie będzie to np. wpisanie "Fizban" pod pole imie), lub wykonanie jakiś czynności na starcie. Czyli mamy "szkielet" i w tym momencie wypełniamy go "mięsem".
  • sama definicja tej funkcji przestrzega wcześniejszych zasad np. warto opisywać typy jakie mają być przekazane
  • bardzo istotne jest tutaj słowo self. Wskazuje one, że przypisujemy cechy do tego konkretnego obiektu, nie do całej klasy.

Odnośniki

„3.12.5 Documentation”. Dostęp 18 sierpień 2024. https://docs.python.org/3/.