IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

Lekce 2 - První objektová aplikace v Pythonu - Hello object world

Minulá lekce, Úvod do objektově orientovaného programování v Pythonu, nás uvedla do objektově orientovaného programování. Již víme, že objekty mají atributy a metody. Také víme, že k vytvoření objektu vytvoříme nejprve třídu. Ta je vzorem, podle kterého následně tvoříme její instance.

Již víme, že objekty mají atributy a metody. Také víme, že k vytvoření objektu vytvoříme nejprve třídu. Ta je vzorem, podle kterého následně tvoříme její instance.

Na začátku kurzu se základními strukturami jazyka Python jsme si vytvořili program Hello world. V tomto tutoriálu Objektově orientovaného programování v Pythonu si napíšeme podobný program, nicméně tentokrát v paradigmatu OOP. Naprogramujme si Hello object world!

Vytvoření třídy

V IDE založíme nový projekt s názvem HelloObjects a vytvoříme soubor zdravic.py. Třídy se vytvářejí klíčovým slovem class. Třídu pojmenujeme Zdravic. Ve třídě bude blok kódu, takže za jméno třídy píšeme dvojtečku. První řádka tedy vypadá takto:

class Zdravic:

Název souboru (modulu) píšeme notací snake_case a třídy naopak notací PascalCase. Na rozdíl od proměnných má tedy každé slovo v názvu třídy velké první písmeno. Název je samozřejmě také bez diakritiky, kterou v programu používáme maximálně uvnitř textových řetězců, nikoli v identifikátorech. Podle této třídy později vytvoříme objekt zdravic, který nás bude umět pozdravit. Vidíme, že se na program již díváme úplně jinak, za každou akci je zodpovědný nějaký objekt. V našem případě se to může zdát zbytečné, nicméně u složitějších aplikací si to budete pochvalovat :)

Nyní si do třídy Zdravic přidáme metodu pozdrav(). Metoda bude veřejně viditelná a nebude mít žádnou návratovou hodnotu ani atributy.

Deklarace metody v Pythonu je podobná deklaraci funkce. Za klíčovým slovem def následuje samotný název metody. Metody píšeme stejně jako proměnné a funkce malými písmeny. V případě víceslovného názvu použijeme notaci snake_case. Závorka s parametry je povinná. První povinný poziční argument je self. Do něj se vloží "odkaz" na objekt, do kterého metoda náleží. Tento argument tam vloží sám objekt. Do těla metody zapíšeme kód pro výpis do konzole.

Naše třída bude nyní vypadat takto:

class Zdravic:
    def pozdrav(self):
        print("Hello object world!")

Všimněme si, že Pythonu dáváme najevo odsazením, že metoda pozdrav() je součástí třídy Zdravic.

Nyní si vytvoříme instanci třídy Zdravic. Bude to tedy ten objekt zdravic, se kterým budeme pracovat. Objekty se ukládají do proměnných, název třídy slouží jako datový typ. Instance má zpravidla název třídy, jen má první písmeno malé. Deklarujme si tedy proměnnou a následně v ní založme novou instanci třídy Zdravic:

zdravic = Zdravic()

Při vytvoření nové instance se zavolá tzv. konstruktor. To je speciální metoda na třídě, proto při vytvoření instance píšeme ty prázdné závorky, jelikož voláme tuto "vytvářecí" metodu. Konstruktor zpravidla obsahuje nějakou inicializaci vnitřního stavu instance (např. dosadí výchozí hodnoty do proměnných). My jsme v kódu žádný konstruktor nedeklarovali a Python si proto vytvořil tzv. implicitní prázdný konstruktor. Vytvoření instance objektu je tedy podobné volání metody.

Jelikož v proměnné nyní máme opravdu instanci třídy Zdravic, můžeme instanci nechat pozdravit. Zavoláme na ni metodu pozdrav() a to jako zdravic.pozdrav(). Náš kód bude tedy nyní vypadat následovně:

class Zdravic:
    def pozdrav(self):
        print("Hello object world!")

zdravic = Zdravic()
zdravic.pozdrav()

Máme tedy svou první objektovou aplikaci!

Přidání parametru

Dejme nyní naší metodě pozdrav() parametr jmeno, aby dokázala pozdravit konkrétního uživatele:

def pozdrav(self, jmeno):
    print(f"Ahoj uživateli {jmeno}!")

Vidíme, že syntaxe parametru metody je stejná, jako syntaxe proměnné. Jednotlivé parametry oddělujeme čárkou. Upravíme také kód pod třídou:

class Zdravic:
    def pozdrav(self, jmeno):
        print(f"Ahoj uživateli {jmeno}!")

zdravic = Zdravic()
zdravic.pozdrav("Karel")
zdravic.pozdrav("Petr")

Náš kód je nyní v metodě a my ho můžeme jednoduše pomocí parametrů volat znovu s různými parametry. Nemusíme dvakrát opisovat "Ahoj uživateli...". Odteď budeme dělit kód logicky do metod:

Výstup metody pozdrav():
Ahoj uživateli Karel!
Ahoj uživateli Petr!

Přidání atributu

Třídě přidáme nějaký atribut. Nabízí se text, kde bude uložen text pozdravu. Atributy se definují stejně jako proměnné. Před jejich název píšeme self. Upravme tedy naši třídu:

class Zdravic:
    text = "nezadaný"                      # definujeme atribut
    def pozdrav(self, jmeno):
        print(f"{self.text} {jmeno}!")     # zde píšeme self před název atributu

zdravic = Zdravic()
zdravic.text = "Ahoj uživateli"
zdravic.pozdrav("Karel")
zdravic.pozdrav("Petr")
zdravic.text = "Vítám tě tu programátore"
zdravic.pozdrav("Richard")

Program nyní zobrazí:

Výstup metody pozdrav():
Ahoj uživateli Karel!
Ahoj uživateli Petr!
Vítám tě tu programátore Richard!

Navracení hodnoty

Vzhledem k objektovému návrhu není nejvhodnější, aby si každý objekt ovlivňoval vstup a výstup jak se mu zachce. Pochopitelně míříme na naše vypisování do konzole. Každý objekt by měl mít určité kompetence, které by neměl překračovat. Pověřme náš objekt pouze sestavením pozdravu a jeho výpis si zpracujeme již mimo. Výhodou takto navrženého objektu je vysoká univerzálnost a znovupoužitelnost. Objekt doposud umí jen psát do konzole. My si jej však přizpůsobíme tak, aby daná metoda text pouze vracela. Bude pak pouze na jeho příjemci, jak s ním naloží. Takto můžeme pozdravy ukládat do souborů, psát na webové stránky nebo dále zpracovávat.

K návratu hodnoty použijeme příkaz return. Return metodu ukončí a navrátí její hodnotu. Jakýkoli další kód v těle metody se po return již neprovede!

Upravíme metodu pozdrav():

def pozdrav(self, jmeno):
    return f"{self.text} {jmeno}!"

A náš program bude nyní vypadat takto:

class Zdravic:
    text = "Ahoj"
    def pozdrav(self, jmeno):
        return f"{self.text} {jmeno}!"

zdravic = Zdravic()
zdravic.text = "Ahoj uživateli"
print(zdravic.pozdrav("Karel"))
print(zdravic.pozdrav("Petr"))
zdravic.text = "Vítám tě tu programátore"
print(zdravic.pozdrav("Richard"))

Kód je nyní napsán dle dobrých praktik.

Přidání komentářů

Ještě naši třídu jak se sluší a patří okomentujme. Komentáře budeme psát pod název třídy a pod název každého atributu a metody. K jejich zápisu použijeme tři dvojité uvozovky ("""). Správně zdokumentovaná třída vypadá např. takto:

class Zdravic:
    """
    Třída reprezentuje zdravič, který slouží ke zdravení uživatelů.
    """

    text = "Ahoj"
    """
    Atribut obsahující výchozí text pozdravu. Pokud není specifikován jiný text,
    použije se tento výchozí text při sestavování pozdravu.
    """

    def pozdrav(self, jmeno):
        """
        Vrátí pozdrav uživatele s nastaveným textem a jeho jménem.

        Parametry:
        - jmeno (str): Jméno osoby, kterou chceme pozdravit.

        Výstup:
        - str: Text pozdravu s jménem osoby.
        """
        return f"{self.text} {jmeno}!"

Vestavěná nápověda - funkce help()

Při čtení kódu často narazíme na třídu, instanci, proměnnou atd., jejíž význam a účel není na první pohled jasný. Funkce help() nám pomůže - zobrazí o daném objektu všechny dostupné detaily. Vezměme naši pečlivě zdokumentovanou třídu Zdravic a vložme ji do nového souboru, například zdravic_hlp.py. Soubor si uložíme a spustíme (spuštění programu je nutné, jinak funkce help() vyhodí chybu). V IDE se potom přepněme do interaktivní konzole. Pro PyCharm je v úplně vlevo jako první z dolního sloupce ikon označená jako Python Console:

Python Console - Objektově orientované programování v Pythonu

Do interaktivní konzole zadáme příkazy:

from zdravic_hlp import Zdravic  #  Třídu do konzole musíme nejprve importovat

help(Zdravic)

Tím se nám zobrazí její popis i popis všech jejích metod a atributů:

Výstup funkce help():
class Zdravic(builtins.object)
 |  Třída reprezentuje zdravič, který slouží ke zdravení uživatelů.
 |
 |  Methods defined here:
 |
 |  pozdrav(self, jmeno)
 |      Vrátí pozdrav uživatele s nastaveným textem a jeho jménem.
 |
 |      Parametry:
 |      - jmeno (str): Jméno osoby, kterou chceme pozdravit.
 |
 |      Výstup:
 |      - str: Text pozdravu s jménem osoby.
 |
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |
 |  __dict__
 |      dictionary for instance variables (if defined)
 |
 |  __weakref__
 |      list of weak references to the object (if defined)
 |
 |  ----------------------------------------------------------------------
 |  Data and other attributes defined here:
 |
 |  text = 'Ahoj'

Pokud chceme v PyCharm informace pouze o konkrétní metodě či proměnné, nastavíme na ni kurzor myši a stiskneme Ctrl + Q.

Význam self

V Pythonu je self jedním z klíčových konceptů v objektově orientovaném programování a je důležité ho pochopit. Když už víme, co je instance a jak se tvoří atributy, pojďme si jej vysvětlit jednoduše a názorně.

Když vytváříme objekt (instanci třídy), představíme si ho jako speciální box. Každý box (objekt) má svá vlastní data (atributy) a nástroje, které s tímto boxem lze dělat (metody). Když chceme, aby box (objekt) něco udělal, potřebujeme způsob, jak na tento konkrétní box odkazovat. A právě self je způsob, kterým toho dosáhneme.

Technické detaily self

V Pythonu se metoda vždy automaticky volá s referencí na objekt, se kterým byla zavolána. Tento objekt se předává jako první parametr metody. Konvencí je, že se tento parametr nazývá self. Když voláme metodu objektu, např. muj_objekt.moje_metoda(), nemusíme self předávat explicitně. Python to za nás udělá automaticky.

Název prvního parametru - self - může být i jiný, ale my se budeme držet zavedených praktik.

Proč self potřebujeme

Když máme více boxů (objektů) stejného typu (třídy), musí metoda vědět, s kterým konkrétním boxem má pracovat. Představme si, že máme v kanceláři a doma dva identické kávovary, protože kafe není nikdy dost :-) Oba kávovary jsou stejného modelu (třídy). Každý kávovar má tedy metodu dopln_vodu(), která slouží k doplnění vody do daného kávovaru. V tomto kontextu je self klíčový.

Jak identifikujeme, kterému kávovaru došla voda? Kdyby kávovary mohly mluvit, řekl by nám kávovar doma, kterému skutečně došla voda: "To já jsem na suchu!". V Pythonu pro to máme self. Díky němu mu dokážeme nařídit: "OK, kávovare (self), doplň si vodu."

Ukažme si příklad reálného kódu:

class Kavovar:
    umisteni = "neznámé místo"
    mnozstvi_vody = 0

    def dopln_vodu(self, mnozstvi):
        self.mnozstvi_vody += mnozstvi
        print(f"Do kávovaru {self.umisteni} bylo doplněno {mnozstvi} ml vody. "
              f"Celkem je v něm nyní {self.mnozstvi_vody} ml vody.")

    def uvar_kavu(self):
        if self.mnozstvi_vody > 100:
            self.mnozstvi_vody -= 100
            print(f"Kávovar {self.umisteni} uvařil kávu. Zbývá {self.mnozstvi_vody} ml vody.")
        else:
            print(f"V kávovaru {self.umisteni} není dostatek vody!")

# Vytvoříme dvě instance kávovaru
kavovar_doma = Kavovar()
kavovar_v_kancelari = Kavovar()

# Nastavíme umístění pro oba kávovary
kavovar_doma.umisteni = "doma"
kavovar_v_kancelari.umisteni = "v kanceláři"

# Doplníme vodu do kávovaru v kanceláři
kavovar_v_kancelari.dopln_vodu(150)

# Zkusíme uvařit kávu v kávovaru doma
kavovar_doma.uvar_kavu()

V konzoli uvidíme výstup:

Použití self:
Do kávovaru v kanceláři bylo doplněno 150 ml vody. Celkem je v něm nyní 150 ml vody.
V kávovaru doma není dostatek vody!

Bez použití self v self.umisteni a self.mnozstvi_vody by metody dopln_vodu() a uvar_kavu() neměly šanci zjistit, jestli je využívá instance kávovaru doma nebo toho v kanceláři. Self tu tedy slouží jako odkaz na konkrétní instanci kávovaru. Pokud bychom self v metodách třídy nepoužili, tyto metody by neměly přístup k datům uloženým v konkrétní instanci třídy a nemohly by provádět operace specifické pro tu danou instanci.

A jsme u konce. Za úkol máte předělat si naši konzolovou kalkulačku do objektů.

V následujícím kvízu, Kvíz - Úvod, objekty, třídy a metody v Pythonu, si vyzkoušíme nabyté zkušenosti z předchozích lekcí.


 

Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.

Stáhnout

Stažením následujícího souboru souhlasíš s licenčními podmínkami

Staženo 832x (3.17 kB)
Aplikace je včetně zdrojových kódů v jazyce Python

 

Předchozí článek
Úvod do objektově orientovaného programování v Pythonu
Všechny články v sekci
Objektově orientované programování v Pythonu
Přeskočit článek
(nedoporučujeme)
Kvíz - Úvod, objekty, třídy a metody v Pythonu
Článek pro vás napsal gcx11
Avatar
Uživatelské hodnocení:
555 hlasů
(^_^)
Aktivity