Vianoce v ITnetwork sú tu! Dobí si teraz kredity a získaj až 80 % extra kreditov na e-learningové kurzy ZADARMO. Zisti viac.
Hľadáme nové posily do ITnetwork tímu. Pozri sa na voľné pozície a pridaj sa k najagilnejšej firme na trhu - Viac informácií.

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 greeter.py. Triedy sa vytvárajú kľúčovým slovom class. Triedu pomenujeme Greeter. V triede bude blok kódu, takže za meno triedy píšeme dvojbodku. Prvý riadok teda vyzerá takto:

class Greeter:

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 greeter, 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 Greeter pridáme metódu greet(). 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 Greeter:
    def greet(self):
        print("Hello object world!")

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

Teraz si vytvoríme inštanciu triedy Greeter. Bude to teda ten objekt greeter, 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 Greeter:

greeter = Greeter()

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 Greeter, môžeme inštanciu nechať pozdraviť. Zavoláme na ňu metódu greet() a to ako greeter.greet(). Náš kód bude teda teraz vyzerať nasledovne:

class Greeter:
    def greet(self):
        print("Hello object world!")

greeter = Greeter()
greeter.greet()

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

Pridanie parametra

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

def greet(self, name):
    print(f"Hello {name}!")

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 Greeter:
    def greet(self, name):
        print(f"Hello {name}!")

greeter = Greeter()
greeter.greet("Carl")
greeter.greet("Peter")

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ť "Hello...". Odteraz budeme deliť kód logicky do metód:

Output of the greet() method:
Hello Carl!
Hello 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 Greeter:
    text = "undefined"                    # defining the attribute
    def greet(self, name):
        print(f"{self.text} {name}!")     # here we use self before the attribute name

greeter = Greeter()
greeter.text = "Hello"
greeter.greet("Carl")
greeter.greet("Peter")
greeter.text = "Hello programmer"
greeter.greet("Richard")

Program teraz zobrazí:

Output of the greet() method:
Hello Carl!
Hello Peter!
Hello programmer 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 greet():

def greet(self, name):
    return f"{self.text} {name}!"

A náš program bude teraz vyzerať takto:

class Greeter:
    text = "Hello"
    def greet(self, name):
        return f"{self.text} {name}!"

greeter = Greeter()
greeter.text = "Hello user"
print(greeter.greet("Carl"))
print(greeter.greet("Peter"))
greeter.text = "Hello programmer"
print(greeter.greet("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 Greeter:
    """
    A class represents a greeter whose purpose is to greet the user.
    """

    text = "Hello"
    """
    An attribute containing the default greeting text.If no other text is specified,
    this default text will be used when creating a greeting.
    """

    def greet(self, name):
        """
        Returns a greeting for the user with the set text and given name.

        Parameters:
        - name(str): The given name of the person we want to greet.

        Output:
        - str: A greeting text with the person's given name.
        """
        return f"{self.text} {name}!"

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 Greeter a vložme ju do nového súboru, napríklad greeter_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

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

from greeter_hlp import Greeter  # We first need to import the class into the console

help(Greeter)

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

Output of the help() function:
class Greeter(builtins.object)
 |  A class represents a greeter whose purpose is to greet the user.
 |
 |  Methods defined here:
 |
 |  greet(self, name)
 |      Returns a greeting for the user with the set text and given name.
 |
 |      Parameters:
 |      - name (str): The given name of the person we want to greet.
 |
 |      Output:
 |      - str: A greeting text with the person's given name.
 |
 |  ----------------------------------------------------------------------
 |  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 = 'Hello'

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. my_object.my_method(), 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 add_water(), 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 CoffeeMaker:
    location = "unknown location"
    water_amount = 0

    def add_water(self, amount):
        self.water_amount += amount
        print(f"{amount} ml of water has been added to the coffee maker at {self.location}."
              f" It now contains {self.water_amount} ml of water.")

    def brew_coffee(self):
        if self.water_amount > 100:
            self.water_amount -= 100
            print(f"The coffee maker at {self.location} brewed coffee. {self.water_amount} ml of water remains.")
        else:
            print(f"There is not enough water in the coffee maker at {self.location}!")

# Create two instances of the coffee maker
coffee_maker_at_home = CoffeeMaker()
coffee_maker_at_office = CoffeeMaker()

# Set the location for both coffee makers
coffee_maker_at_home.location = "home"
coffee_maker_at_office.location = "the office"

# Add water to the coffee maker at the office
coffee_maker_at_office.add_water(150)

# Try to brew coffee in the coffee maker at home
coffee_maker_at_home.brew_coffee()

V konzole uvidíme výstup:

Usage of self:
150 ml of water has been added to the coffee maker at the office. It now contains 150 ml of water.
There is not enough water in the coffee maker at home!

Bez použitia self v self.location a self.water_amount by metódy add_water() a brew_coffee() 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é 0x (1.82 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:
7 hlasov
(^_^)
Aktivity