Python 3 Class

Python

Obiekty to połączenie zmiennych i funkcji w jedną strukturalną całość. Obiekty biorą swoje zmienne i funkcje z klas. Klasa to podstawowy schemat, według którego tworzone są obiekty.

Nim nauczymy się tworzyć klasy, nauczmy się paru ważnych słówek:

class (klasa) – Python jest informowany że tworzymy nowy typ rzeczy.

Obiekt – ma dwa znaczenia: najbardziej podstawowy typ rzeczy oraz każda instancja jakiejś rzeczy.

Instancja – to, co otrzymujesz gdy powiesz Pythonowi, aby utworzył klasę.

def– sposób definiowania funkcji wewnątrz klasy.

self – wewnętrzna funkcja w klasie self jest zmienną dla instancji (obiektu), do której uzyskujemy dostęp.

Dziedziczenie – koncepcja, że jedna klasa może dziedziczyć cechy po innej klasie podobnie jak Ty możesz dziedziczyć po rodzicach.

Kompozycja – koncepcja, że klasa może być skomponowana (składać się) z innych klas jako część, podobnie jak samochód ma koła.

Atrybut – właściwość klasy wynikająca z kompozycji i zazwyczaj będąca zmienną.

Jest (ang. is-a) – wyrażenie, które mówi, że coś odziedziczy po czymś innym, na przykład „łosoś” jest „rybą

Ma (ang. has-a) – wyrażenie, które mówi, że coś jest skomponowane z innych rzeczy lub ma jakąś cechę, np „łosoś” ma „usta„.

 

 

Tworzenie klas


# 'class' mówi Pythonowi że tworzona jest klasa. 
# Nazwy klas zaczynamy zawsze z dużej litery i nie stosujemy nazw z _ (podłogą).
# 'object' do wersji 2.6, w python 3 i wyżej możemy pominąć, ale dla czytelności lepiej pozostawić.
class Calc(object):
    
    # metoda dodawanie klasy Calc()
    def dodawanie(self, x, y):
         print(x + y)

    # metoda odejmowania klasy Calc()
    def odejmowanie(self, x, y):
         print(x + y)


# Instancja klasy
a = Calc()
# wywołanie metody dodawania na instancji 'a' klasy Calc() 
a.dodawanie(2, 4)
# wywołanie metody odejmowania na instancji 'a' klasy Calc()
a.odejmowanie(10, 7)

 

 

Ważnym wymogiem w Pythonie jest by pierwszy argument w metodzie ( def dodawanie() oraz def odejmowanie() ), pod który podstawiana jest instancja nazywał się self  co z ang. oznacza „własne ja„, „ja sam„.  Czyli klasa powinna wyglądać mniej więcej tak:


class JakasKlasa(object):
    
    def metoda (self, drugi_argument):
        print("Oto", self, drugi_argument)

 

 

Specjalne metody

W Pythonie występują magiczne metody, które odgórnie mają przypisaną funkcję. Każda specjalna metoda zaczyna się od dwóch podkreśleń (podłogi) i nie należy wprowadzać samemu takiego rodzaju nazw. Do takich metod należy __init__ wywoływana jest automatycznie zaraz po utworzeniu nowej instancji – jest więc ona dobrym miejscem na ustawienie artybutów instancji, których będziemy używać. Metoda __init__() nazywana bywa konstruktorem (nie do końca słusznie, bo w momencie jej wykonywania instancja klasy już istnieje).

 


class Samochod(object):
    
    kolejny_nr_seryjny = 1  # atrybut klasy
    def __init__(self):  # self to nowo utworzona instancja
        # ustawiamy atrybuty instancji (teraz widzimy, po co nam self)
        self.predkosc = 0
        self.nr_seryjny = self.kolejny_nr_seryjny  # używamy atrybutu klasy "kolejny_nr_seryjny"
        # zwiększamy wartość atrybutu klasy "kolejny_nr_seryjny"
        self.__class__.kolejny_nr_seryjny = self.kolejny_nr_seryjny + 1
        # (^ mamy tu operację przypisania, dlatego dobieramy się
        #  do atrybutu poprzez klasę - by przypisać wartość atrybutowi
        #  klasy, a *nie* przesłonić atrybut klasy atrybutem instancji
        #  o identycznej nazwie)
        print ("nr", self.nr_seryjny)
    
    def wypisz_predkosc(self):
        print ("nr", self.nr_seryjny, "- predkosc:", self.predkosc, "km/h")
    
    def dodaj_gazu(self, o_ile):
        self.predkosc += o_ile
        self.wypisz_predkosc()
    
    def hamuj(self, o_ile):
        self.predkosc -= o_ile
        self.wypisz_predkosc()
 

s1 = Samochod()  # -> nr 1
s2 = Samochod()  # -> nr 2
s1.dodaj_gazu(50)  # -> nr 1 - predkosc: 50 km/h
s2.dodaj_gazu(30)  # -> nr 2 - predkosc: 30 km/h
s1.hamuj(28)  # -> nr 1 - predkosc: 22 km/h
s2.hamuj(28)  # -> nr 2 - predkosc: 2 km/h
 
Samochod.kolejny_nr_seryjny = 100
s3 = Samochod()  # -> nr 100
Samochod.kolejny_nr_seryjny = 0
s4 = Samochod()  # -> nr 0

 

Dziedziczenie

Definiowanie kilku klas, które posiadają wspólne cechy, czyli dziedziczenie. Tak samo jak Ty dziedziczysz po rodzicach pewne cechy, tak klasy mogą dziedziczyć po sobie.
Istnieją trzy sposoby interakcji klasy nadrzędnej czyli rodzica (ang. parent) i klasy potomnej, czyli dziecka (ang. child).

  1. Działania na dziecku implikują działanie na rodzicu.
  2. Działania na dziecku nadpisują działa na rodzicu.
  3. Działania na dziecku zmieniają działanie na rodzicu.

 

Dziedziczenie domyślne


class Parent(object):

    def implicit(self):
        print("RODZIC implicit()")

class Child(Parent):
    pass

dad = Parent()
son = Child()

dad.implicit()
son.implicit()

Używając pass pod klasą Child: informuje Pythona że potrzebuję pustego bloku. To tworzy klasę o nazwie Child, ale mówi, że nie ma w niej nic nowego do zdefiniowania. Zamiast tego odziedziczy ona wszystkie zachowania z klasy Parent.
Zauważyć należy iż mimo że Child nie ma zdefiniowanej funkcji implicit, to wywołuję funkcję zdefiniowaną w klasie Parent ( son.implicit() ). Oznacza to że, jeśli w klasie bazowej (Parent) umieszczę funkcję, wszystkie podklasy (np. Child) automatycznie pobiorą te funkcjonalność. Jest to przydatne w przypadku powtarzających się kodów, których potrzebujesz w wielu klasach.

 

Nadpisanie

Czasami jednak chcesz by dziecko zachowało się inaczej. W tym przypadku chce nadpisać funkcję w klasie potomnej, w efekcie zastępując funkcjonalność. W tym celu po prostu definiujemy w klasie Child funkcję o tej samej nazwie:

 


class Parent(object):

    def override(self):
        print("RODZIC override()")

class Child(Parent):

    def override(self):
        print("Dziecko override()")

dad = Parent()
son - Child()

dad.override()
son.override()

 

Jak widać dad.override() powoduje uruchomienie funkcji Parent.override, ponieważ ta zmienna (dad) to Parrent. Kiedy jednak zostaje uruchomiony kod son.override() drukowany jest komunikat funkcji Child.override, ponieważ son jest instancją klasy Child, a Child nadpisuje tę funkcję poprzez zdefiniowanie jej własnej wersji.

 

Zmiana zachowania przed lub po

Jeśli chcemy nadpisać zachowanie funkcji przed uruchomieniem jej wersji z klasy Parent, lub po, najpierw nadpisujemy tę funkcję jak w poprzednim przykładzie, ale potem używamy wbudowanej funkcji Pythona o nazwie super, aby pobrać do wywołania wersję z klasy Parent.

 


class Parent(object):

    def altered(self):
        print("RODZIC altered()")

class Child(Parent):

    def altered(self):
        print("DZIECKO PRZED altered() RODZICA")
        super(Child, self).altered()
        print("DZIECKO PO altered() RODZICA")

dad = Parent()
son = Child()

dad.altered()
son.altered()

Podczas wywoływania son.altered() robię w klasie Child następujące rzeczy:

  1. Ponieważ nadpisałem Parent.altered, uruchamiana jest wersja Child.altered, a w linia 10 wykonywana jest tak, jakby tego oczekiwał.
  2. W tym przypadku robię zamianę przed i po, więc po linii 10, używam funkcji super, aby pobrać wersję Parent.altered.
  3. W linii 11 wywołuję funkcję super(Child, self).altered(), która jest świadoma dziedziczenia i pobierze klasę Parent. Odczytujemy to mniej więcej tak: „Wywołaj super z argumentami Child i self, a następnie wywołaj funkcję altered na tym, co zostanie zwrócone”.
  4. W tym momencie uruchamiana jest wersja Parent.altered funkcji, która drukuje komunikat klasy Parent.
  5. Wreszcie funkcja Parent.altered kończy wykonywanie i uruchamiana zostaje funkcja Child.altered, która drukuje komunikat „po”.

 

Połączenie wszystkich sposobów na raz


class Child(Parent):
    
    # Funkcja wyświetla override dziecka.
    def override(self):
        print("DZIECKO override()")
    
    # Funkcja drukuje altered dziecka i rodzica nadpisując
    def altered(self):
        # Drukuje przed wyświetleniem rodzica
        print("DZIECKO PRZED altered() RODZICA")
        # Drukuje altered Rodzica
        super(Child, self).altered()
        # Drukuje po wyświetleniu altered rodzica
        print("DZIECKO PO altered() RODZICA")

dad = Parent()
son = Child()

# Rodzic
dad.implicit()
# Pobiera od Rodzica
son.implicit()

# Rodzic
dad.override()
# Zmienia Rodzica
son.override()

# Drukuje Rodzica
dad.altered()
# Drukuje Przed i Po rodzicu
son.altered()

Input:

>>> 
RODIC implicit()
RODIC implicit()
RODZIC override()
DZIECKO override()
RODZIC altered()
DZIECKO PRZED altered() RODZICA
RODZIC altered()
DZIECKO PO altered() RODZICA

1 komentarz do wpisu “Python 3 Class”

Dodaj komentarz