IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

2. diel - Prvá objektová aplikácia v Pythone - Hello object world

Minulá lekcia, Úvod do objektovo orientovaného programovania v Pythone , nás uviedla do objektovo orientovaného programovania.

Už vieme, že objekty majú atribúty a metódy. Tiež vieme, že na vytvorenie objektu vytvoríme najprv triedu. Tá je vzorom, podľa ktorého následne tvoríme jej inštancie.

Na začiatku kurzu so základnými štruktúrami jazyka Python sme si vytvorili program Hello world. V tomto tutoriále Objektovo orientovaného programovania v Pythone si napíšeme podobný program, avšak tentoraz v paradigme OOP. Naprogramujme si Hello object world !

Vytvorenie triedy

V IDE založíme nový projekt s názvom HelloObjects a vytvoríme súbor zdravic.py. Triedy sa vytvárajú kľúčovým slovom class. Triedu pomenujeme Zdravic. V triede bude blok kódu, takže za meno triedy píšeme dvojbodku. Prvý riadok teda vyzerá takto:

class Zdravic:

Názov súboru (modulu) píšeme notáciou snake_case a triedy naopak notáciou PascalCase. Na rozdiel od premenných má teda každé slovo v názve triedy veľké prvé písmeno. Názov je samozrejme tiež bez diakritiky, ktorú v programe používame maximálne vo vnútri textových reťazcov, nie v identifikátoroch. Podľa tejto triedy neskôr vytvoríme objekt zdravic, ktorý nás bude vedieť pozdraviť. Vidíme, že sa na program už pozeráme úplne inak, za každú akciu je zodpovedný nejaký objekt. V našom prípade sa to môže zdať zbytočné, avšak pri zložitejších aplikáciách si to budete pochvaľovať:)

Teraz si do triedy Zdravic pridáme metódu pozdrav(). Metóda bude verejne viditeľná a nebude mať žiadnu návratovú hodnotu ani atribúty.

Deklarácia metódy v Pythone je podobná deklarácii funkcie. Za kľúčovým slovom def nasleduje samotný názov metódy. Metódy píšeme rovnako ako premenné a funkcie malými písmenami. V prípade viacslovného názvu použijeme notáciu snake_case. Zátvorka s parametrami je povinná. Prvý povinný pozičný argument je self. Do neho sa vloží "odkaz" na objekt, do ktorého metóda patrí. Tento argument tam vloží sám objekt. Do tela metódy zapíšeme kód na výpis do konzoly.

Naša trieda bude teraz vyzerať takto:

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

Všimnime si, že Pythonu dávame najavo odsadením, že metóda pozdrav() je súčasťou triedy Zdravic.

Teraz si vytvoríme inštanciu triedy Zdravic. Bude to teda ten objekt zdravic, s ktorým budeme pracovať. Objekty sa ukladajú do premenných, názov triedy slúži ako dátový typ. Inštancia má spravidla názov triedy, len má prvé písmeno malé. Deklarujme si teda premennú a následne v nej založme novú inštanciu triedy Zdravic:

zdravic = Zdravic()

Pri vytvorení novej inštancie sa zavolá tzv. konštruktor. To je špeciálna metóda na triede, preto pri vytvorení inštancie píšeme tie prázdne zátvorky, pretože voláme túto "vytváraciu" metódu. Konštruktor spravidla obsahuje nejakú inicializáciu vnútorného stavu inštancie (napr. dosadí východiskové hodnoty do premenných). My sme v kóde žiadny konštruktor nedeklarovali a Python si preto vytvoril tzv. implicitný prázdny konštruktor. Vytvorenie inštancie objektu je teda podobné volanie metódy.

Keďže v premennej teraz máme naozaj inštanciu triedy Zdravic, môžeme inštanciu nechať pozdraviť. Zavoláme na ňu metódu pozdrav() a to ako zdravic.pozdrav(). Náš kód bude teda teraz vyzerať nasledovne:

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

zdravic = Zdravic()
zdravic.pozdrav()

Máme teda svoju prvú objektovú aplikáciu!

Pridanie parametra

Dajme teraz našej metóde pozdrav() parameter jmeno, aby dokázala pozdraviť konkrétneho užívateľa:

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

Vidíme, že syntax parametra metódy je rovnaká, ako syntax premennej. Jednotlivé parametre oddeľujeme čiarkou. Upravíme tiež kód pod triedou:

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

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

Náš kód je teraz v metóde a my ho môžeme jednoducho pomocou parametrov volať znova s rôznymi parametrami. Nemusíme dvakrát opisovať "Ahoj užívateľovi...". Odteraz budeme deliť kód logicky do metód:

Výstup metody pozdrav():
Ahoj užívateľovi Karel!
Ahoj užívateľovi Peter!

Pridanie atribútu

Triede pridáme nejaký atribút. Ponúka sa text, kde bude uložený text pozdravu. Atribúty sa definujú rovnako ako premenné. Pred ich názov píšeme self. Upravme teda našu triedu:

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 teraz zobrazí:

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

Vrátenie hodnoty

Vzhľadom k objektovému návrhu nie je najvhodnejšie, aby si každý objekt ovplyvňoval vstup a výstup ako sa mu zachce. Pochopiteľne mierime na naše vypisovanie do konzoly. Každý objekt by mal mať určité kompetencie, ktoré by nemal prekračovať. Poverme náš objekt iba zostavením pozdravu a jeho výpis si spracujeme už mimo. Výhodou takto navrhnutého objektu je vysoká univerzálnosť a znovupoužiteľnosť. Objekt doteraz vie len písať do konzoly. My si ho však prispôsobíme tak, aby daná metóda text iba vracala. Bude potom iba na jeho príjemcovi, ako s ním naložia. Takto môžeme pozdravy ukladať do súborov, písať na webové stránky alebo ďalej spracovávať.

Na návrat hodnoty použijeme príkaz return. Return metódu ukončí a vráti jej hodnotu. Akýkoľvek ďalší kód v tele metódy sa po return už nevykoná!

Upravíme metódu pozdrav():

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

A náš program bude teraz vyzerať 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 teraz napísaný podľa dobrých praktík.

Pridanie komentárov

Ešte našu triedu ako sa pristane a patrí okomentujme. Komentáre budeme písať pod názov triedy a pod názov každého atribútu a metódy. Na ich zápis použijeme tri dvojité úvodzovky ("""). Správne zdokumentovaná trieda vyzerá napr. 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}!"

Vstavaná nápoveda - funkcia help()

Pri čítaní kódu často narazíme na triedu, inštanciu, premennú atď., ktorej význam a účel nie je na prvý pohľad jasný. Funkcia help() nám pomôže - zobrazí o danom objekte všetky dostupné detaily. Zoberme našu starostlivo zdokumentovanú triedu Zdravic a vložme ju do nového súboru, napríklad zdravic_hlp.py. Súbor si uložíme a spustíme (spustenie programu je nutné, inak funkcia help() vyhodí chybu). V IDE sa potom prepnime do interaktívnej konzoly. Pre PyCharm je v úplne vľavo ako prvá z dolného stĺpca ikon označená ako Python Console:

Python Console - Objektovo orientované programovanie v Pythone - Objektovo orientované programovanie v Pythone

Do interaktívnej konzoly zadáme príkazy:

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

help(Zdravic)

Tým sa nám zobrazí jej popis aj popis všetkých jej metód a atribútov:

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'

Pokiaľ chceme v PyCharm informácie iba o konkrétnej metóde či premennej, nastavíme na ňu kurzor myši a stlačíme Ctrl + Q.

Význam self

V Pythone je self jedným z kľúčových konceptov v objektovo orientovanom programovaní a je dôležité ho pochopiť. Keď už vieme, čo je inštancia a ako sa tvoria atribúty, poďme si ho vysvetliť jednoducho a názorne.

Keď vytvárame objekt (inštanciu triedy), predstavíme si ho ako špeciálny box. Každý box (objekt) má svoje vlastné dáta (atribúty) a nástroje, ktoré s týmto boxom je možné robiť (metódy). Keď chceme, aby box (objekt) niečo urobil, potrebujeme spôsob, ako na tento konkrétny box odkazovať. A práve self je spôsob, ktorým to dosiahneme.

Technické detaily self

V Pythone sa metóda vždy automaticky volá s referenciou na objekt, s ktorým bola zavolaná. Tento objekt sa odovzdáva ako prvý parameter metódy. Konvenciou je, že sa tento parameter nazýva self. Keď voláme metódu objektu, napr. muj_objekt.moje_metoda(), nemusíme self odovzdávať explicitne. Python to za nás urobí automaticky.

Názov prvého parametra – self – môže byť aj iný, ale my sa budeme držať zavedených praktík.

Prečo self potrebujeme

Keď máme viac boxov (objektov) rovnakého typu (triedy), musí metóda vedieť, s ktorým konkrétnym boxom má pracovať. Predstavme si, že máme v kancelárii a doma dva identické kávovary, pretože kávu nie je nikdy dosť:-) Oba kávovary sú rovnakého modelu (triedy). Každý kávovar má teda metódu dopln_vodu(), ktorá slúži na doplnenie vody do daného kávovaru. V tomto kontexte je self kľúčový.

Ako identifikujeme, ktorému kávovaru došla voda? Keby kávovary mohli hovoriť, povedal by nám kávovar doma, ktorému skutočne došla voda: „To ja som na suchu!“. V Pythone pre to máme self. Vďaka nemu mu dokážeme nariadiť: "OK, kávovar (self), doplň si vodu."

Ukážme si príklad reálneho kódu:

class Kavovar:
    umisteni = "neznáme miesto"
    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} uvaril kávu. Zostáva {self.mnozstvi_vody} ml vody.")
        else:
            print(f"V kávovare {self.umisteni} nie je dostatok 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 konzole 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žitia self v self.umisteni a self.mnozstvi_vody by metódy dopln_vodu() a uvar_kavu() nemali šancu zistiť, či ich využíva inštancia kávovaru doma alebo toho v kancelárii. Self tu teda slúži ako odkaz na konkrétnu inštanciu kávovaru. Pokiaľ by sme self v metódach triedy nepoužili, tieto metódy by nemali prístup k dátam uloženým v konkrétnej inštancii triedy a nemohli by vykonávať operácie špecifické pre tú danú inštanciu.

A sme na konci. Za úlohu máte prerobiť si našu konzolovú kalkulačku do objektov.

V nasledujúcom kvíze, Kvíz - Úvod, objekty, triedy a metódy v Pythone, si vyskúšame nadobudnuté skúsenosti z predchádzajúcich lekcií.


 

Mal si s čímkoľvek problém? Stiahni si vzorovú aplikáciu nižšie a porovnaj ju so svojím projektom, chybu tak ľahko nájdeš.

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 893x (3.17 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python

 

Predchádzajúci článok
Úvod do objektovo orientovaného programovania v Pythone
Všetky články v sekcii
Objektovo orientované programovanie v Pythone
Preskočiť článok
(neodporúčame)
Kvíz - Úvod, objekty, triedy a metódy v Pythone
Článok pre vás napísal gcx11
Avatar
Užívateľské hodnotenie:
6 hlasov
(^_^)
Aktivity