Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
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í.

3. diel - Hracia kocka v Pythone - Konštruktory a náhodné čísla

V predchádzajúcom cvičení, Riešené úlohy k 1.-2. lekciu OOP v Pythone, sme si precvičili získané skúsenosti z predchádzajúcich lekcií.

V minulej lekcii, Riešené úlohy k 1.-2. lekciu OOP v Pythone , sme si naprogramovali prvú objektovú aplikáciu. Už vieme tvoriť nové triedy a vkladať do nich atribúty a metódy s parametrami a návratovú hodnotou. Dnes v Python tutoriálu začneme pracovať na sľúbené aréne, v ktorej budú proti sebe bojovať dvaja bojovníci. Boj bude ťahový (na preskáčku) a bojovník vždy druhému uberie život na základe sily jeho útoku a obrany druhého bojovníka. Simulujeme v podstate stolný hru, budeme teda simulovať aj hraciu kocku, ktorá dodá hre prvok náhodnosti. Začnime zvoľna a vytvorme si dnes práve túto hraciu kocku. Zároveň sa naučíme ako definovať vlastné konštruktor.

Založíme si nový súbor a pomenujeme ho Arena. Vytvoríme novú triedu s názvom Kocka. Zamyslime sa nad atribúty, ktoré kocke dáme. Iste by sa hodilo, keby sme si mohli zvoliť počet stien kocky (klasicky 6 alebo 10 stien, ako je zvykom u tohto typu hier). Ďalej bude kocka potrebovať tzv. Generátor náhodných čísel. Ten nám samozrejme poskytne modul random, ktorý na tieto účely obsahuje metódu randint(). Naša trieda bude mať teraz atribút: pocet_sten. Minule sme kvôli jednoduchosti nastavovali všetky atribúty našej triedy ako verejne prístupné. Väčšinou sa však skôr nechce, aby sa dali zvonku modifikovať a preto sa nastavujú ako súkromné. Súkromné atribúty začínajú dvoma podtržníkmi. K atribútu potom nedá normálne pristupovať. Pri návrhu triedy teda použijeme pre atribúty podčiarknutia a v prípade, že niečo bude naozaj potrebné vystaviť, je nepoužijeme. Naša trieda zatiaľ vyzerá asi takto, atribúty pridáme až neskôr:

class Kostka:
    """
    Třída reprezentuje hrací kostku.
    """

Konštruktory

Až doteraz sme nevedeli zvonku nastaviť iné atribúty ako verejné, pretože súkromné atribúty nie sú zvonku viditeľné. Tento problém sa dá obísť pomocou komolenie mien (tzv. Name mangling), ale vzhľadom na zapuzdrenie to nie je dobrá praktika. Už sme si hovorili niečo málo o konstruktoru objektu. Je to metóda, ktorá sa zavolá vo chvíli vytvorenia inštancie objektu. Slúži samozrejme k nastavenie vnútorného stavu objektu a na vykonanie prípadnej inicializácia. Kocku teraz vytvoríme takto:

kostka = Kostka()

Práve Kocka () je konštruktor. Pretože v našej triede žiadny nie je, Python si dogeneruje prázdnu metódu. My si však teraz konštruktor do triedy pridáme. Deklaruje sa ako metóda. V Pythone môžeme použiť metódy hneď dve. Metódu __new __ () a metódu __init __ (). Tá prvá sa volá pri vytváraní objektu, ale väčšinou si vystačíme so druhú metódu, ktorá sa volá pri inicializácii objektu. Metódu konstruktoru budeme moji prázdnu. Samozrejme ako prvý parameter píšeme self. Do metódy vložíme ďalšie kľúčové slovo pass, ktoré Pythone hovorí, aby nič nerobil. Ak by tam to slovo nebolo, Python by nám vyhodil chybu, že očakáva blok príkazov.

def __init__(self):
    pass

Ak v metóde __init__ len tak vytvoríme nejakú premennú, tak tá po ukončení metódy zaniká. Ale my potrebujeme vytvoriť atribút pocet_sten. Atribúty objektov sa vytvárajú všemocným slovkom self. Za self nasleduje bodka a názov atribútu. Vytvoríme teda verejný atribút pocet_sten.

def __init__(self):
    self.pocet_sten = 6

Ak kocku teraz vytvoríme, bude mať atribút pocet_sten nastavený na 6. Vypíšme si počet stien do konzoly, nech vidíme, že tam hodnota naozaj je. Celý kód:

class Kostka:
    """
    Třída reprezentuje hrací kostku.
    """

    def __init__(self):
        self.pocet_sten = 6


kostka = Kostka()
print(kostka.pocet_sten)
input()

Nie je dobré atribút nastaviť ako verejný, pretože nebudeme chcieť, aby nám niekto mohol už u vytvorenej kocky meniť počet stien. Pridáme do triedy teda metódu vrat_pocet_sten (), ktorá nám vráti hodnotu atribútu pocet_sten a tento atribút upravíme na neverejný. Docielime tým v podstate toho, že je atribút read-only (atribút nie je viditeľný a možno ho len čítať metódou, zmeniť ho nemožno). Python má na tento účel ešte ďalšie konštrukcie, ale tým sa zatiaľ nebudeme zaoberať. Upravená verzia triedy i metódou:

class Kostka:
    """
    Třída reprezentuje hrací kostku.
    """

    def __init__(self):
        self.__pocet_sten = 6

    def vrat_pocet_sten(self):
        """
        Vrátí počet stěn kostky.
        """
        return self.__pocet_sten


kostka = Kostka()
print(kostka.vrat_pocet_sten())
input()

Atribút sa stal súkromným pridaním dvoch podčiarkovníkov. Navyše sme zmenili vypisovanie, pretože hodnotu atribútu zistíme len zavolaním metódy.

výstup:

6

Vidíme, že sa konštruktor naozaj zavolal. My by sme ale chceli, aby sme mohli pri každej kocky pri vytvorení špecifikovať, koľko stien budeme potrebovať. Dáme teda konstruktoru parameter:

def __init__(self, pocet_sten):
    self.__pocet_sten = pocet_sten

Všimnite si, že názvy atribútu a argumentu sú skoro rovnaké. Ak by sme mali počet stien ako verejný atribút, tak rovnaký názov nevadí. Pomocou self špecifikujeme, že ľavá premenná pocet_sten náleží inštanciu, pravú Python chápe ako z parametra (argumentu). S verejným atribútom by situácia vyzerala takto:

def __init__(self, pocet_sten):
    self.pocet_sten = pocet_sten

Ale vráťme sa k pôvodnému kódu a skúsme si zadať parameter do konstruktoru.

kostka = Kostka(10) # v tuto chvíli se zavolá konstruktor s par. 10
print(kostka.vrat_pocet_sten())
input()

výstup:

10

Všetko funguje, ako sme očakávali. Python nám už v tejto chvíli nevygeneruje prázdny (tzv. Bezparametrický konštruktor), takže kocku bez parametra už vytvoriť nedá. My to však môžeme umožniť pomocou uvedenia predvolené hodnoty argumentu pocet_sten v definícii konstruktoru. Nastavíme ju na 6, pretože takú hodnotu asi užívateľ našej triedy u kocky očakáva ako predvolený:

def __init__(self, pocet_sten=6):
    self.__pocet_sten = pocet_sten

Skúsme si teraz vytvoriť 2 inštancie kocky, jednu bez udania počtu stien a jednu s ním:

sestistenna = Kostka()
desetistenna = Kostka(10) #nebo můžeme mít Kostka(pocet_sten=10)
print(sestistenna.vrat_pocet_sten())
print(desetistenna.vrat_pocet_sten())
input()

výstup:

6
10

Vďaka kľúčovému argumentu nemusíme počet stien zadávať. Toho môžeme využívať aj u všetkých ďalších metód, nielen u konstruktoru. Mnoho funkcií a metód v Pythone má kľúčové argumenty, napr. Vstavaná funkcia print (). Je dobré si u metód prejsť ich kľúčové argumenty, aby ste neprogramoval niečo, čo už niekto urobil pred vami. Máme teda konštruktor, ktorý nám umožňuje tvoriť rôzne hracie kocky. Prejdime ďalej.

Náhodné čísla

Definujme na kocke metódu hod (), ktorá nám vráti náhodné číslo od 1 do počtu stien. Metóda nebude mať žiadny parameter. Náhodné číslo získame tak, za pomoci modulu random. Modul si importujete vnútorne (použijeme jedno znak podčiarknutia). A použijeme metódu randint ().

def hod(self):
    """
    Vykoná hod kostkou a vrátí číslo od 1 do
    počtu stěn.
    """
    import random as _random
    return _random.randint(1, self.__pocet_sten)

Pri importovaní modulov sa Python pozrie, či bol už modul importovaný, takže ak modul importoval skôr, tak ho Python znova neimportujete. Teda sa prvý riadok v metóde vykoná len raz.

Prekrývanie metódy __str__

Kocka je takmer hotová, ukážme si ešte jednu užitočnú metódu, ktorú si pridáme a ktorú budeme hojne používať aj vo väčšine našich ďalších objektov. Reč je o metóde __str__, o ktorej sme sa zatiaľ nezmienili a ktorú obsahuje každý objekt, teda aj teraz naše kocka. Metóda je určená na to, aby vrátila tzv. Textovú reprezentáciu inštancie. Hodí sa vo všetkých prípadoch, kedy si inštanciu potrebujeme vypísať alebo s ňou pracovať ako s textom. Túto metódu majú napr. Aj čísla. V Pythone funguje implicitné konverzie, akonáhle teda budeme chcieť do konzoly vypísať číslo alebo ktorýkoľvek iný objekt, Python na ňom zavolá metódu __str__ a vypíše jej výstup. Ak si robíme vlastný triedu, mali by sme zvážiť, či sa nám takáto metóda nehodí. Nikdy by sme si nemali robiť vlastnú metódu, napr. Niečo ako vypis (), keď máme v Pythone pripravenú cestu, ako toto riešiť. U kocky nemá __str__ vyšší zmysel, ale u bojovníka bude určite vracať jeho meno. My si ju ku kocke rovnako pridáme, bude vypisovať, že sa jedná o kocku a vráti aj počet stien. Najprv si skúsme vypísať do konzoly našu inštanciu kocky:

print(sestistenna)

Do konzoly sa vypíše iba cesta k našej triede. Hoci je metóda už definovaná, môžeme ju jednoducho definovať znova a tým ju prekryjeme.

def __str__(self):
    """
    Vrací textovou reprezentaci kostky.
    """
    return str("Kostka s {0} stěnami".format(self.__pocet_sten))

Teraz opäť skúsime do konzoly vypísať priamo inštanciu kocky.

výstup:

Kostka s 6 stěnami

Ešte si naše kocky vyskúšame. Skúsime si v programe s našimi dvoma kockami v cykloch hádzať a pozrieme sa, či fungujú tak, ako sa očakáva. Upravíme koniec súboru:

# vytvoření kostek
sestistenna = Kostka()
desetistenna = Kostka(10)

#hod šestistěnnou
print(sestistenna)
for _ in range(10):
    print(sestistenna.hod(), end=" ")

#hod desetistěnnou
print("\n", desetistenna, sep="")
for _ in range(10):
    print(desetistenna.hod(), end=" ")

input()

Za for nasleduje podčiarkovník, pretože robiť niečo s premennou v cykle nepotrebujeme.

Výstup môže vyzerať nejako takto:

Objektová hracia kocka v C # - Objektovo orientované programovanie v Pythone

Máme hotovú celkom peknú a nastaviteľnou triedu, ktorá reprezentuje hraciu kocku. Bude sa nám hodiť v našej aréne, ale môžete ju použiť aj kdekoľvek inde. Vidíme, ako OOP umožňuje znovu používať komponenty. V budúcej lekcii, Riešené úlohy k 3. lekcii OOP v Pythone , sa zameriame na to, ako sa s objektmi pracuje v pamäti.

V nasledujúcom cvičení, Riešené úlohy k 3. lekcii OOP v Pythone, si precvičíme nadobudnuté skúsenosti z predchádzajúcich lekcií.


 

Predchádzajúci článok
Riešené úlohy k 1.-2. lekciu OOP v Pythone
Všetky články v sekcii
Objektovo orientované programovanie v Pythone
Preskočiť článok
(neodporúčame)
Riešené úlohy k 3. lekcii OOP v Pythone
Článok pre vás napísal gcx11
Avatar
Užívateľské hodnotenie:
4 hlasov
(^_^)
Aktivity