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:
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é 890x (3.17 kB)
Aplikácia je vrátane zdrojových kódov v jazyku Python