Jarní BF Python týden
100% homeoffice, 100% časově flexibilní fulltime programátor pro ITnetwork.cz. #bezdeadlinu Mám zájem!
Využij Jarní akci a získej od nás 50 % bodů navíc zdarma! Zároveň také probíhá Python týden se slevou na e-learning až 80 %

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
Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!

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 #

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í.


 

Stiahnuť

Stiahnuté 452x (940 B)
Aplikácia je vrátane zdrojových kódov v jazyku python

 

 

Aktivity (1)

 

 

Komentáre

Avatar
mixxy
Člen
Avatar
mixxy:8.8.2019 23:01

Ahoj,
jakou mas verzi Pythonu? Ja jsem to zkousel na telefonu a bez problemu. Muzes si zkusit nadefinovat ve tride tu promennou __pocet_sten.

Odpovedať
8.8.2019 23:01
Neni dulezite mnoho vedet a znat. Dulezite je vedet, co je treba.
Avatar
Odpovedá na mixxy
Jan Koloničný:10.8.2019 17:07

Mám Python 3.7.2. Myslíš, že v tom může být problém?

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

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

    def vrat_pocet_sten(self):
        return self.__pocet_sten


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

A píše mi to: AttributeError: 'Kostka' object has no attribute '_Kostka__pocet_sten'

 
Odpovedať
10.8.2019 17:07
Avatar
Odpovedá na Jan Koloničný
Jan Koloničný:10.8.2019 17:39

Chyba byla u mě :D spouštěl jsem úplně něco jiného, než jsem psal :D

 
Odpovedať
10.8.2019 17:39
Avatar
josef rajmon
Člen
Avatar
josef rajmon:22.9.2019 20:44

ahoj mam problem kdyz se dostanu k definovaní vrat_pocet_sten tak mi to zatim hodí
syntax error expected of indented block a absolutne nevim co s tím muze mi nekdo poradit?

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

def __init__(self):
self.__pocet_sten = 6

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

kostka = Kostka()
print(kostka.vrat_po­cet_sten())
input()

 
Odpovedať
22.9.2019 20:44
Avatar
hanpari
Redaktor
Avatar
Odpovedá na josef rajmon
hanpari:23.9.2019 17:14

Neocekavane odsazeni.
Python od tebe ceka, ze budes odsazovat kod, protoze jeho bloky se neoddeluji zavorkami, ale bilymi znaky na zacatku radky, mezery nebo tabulatory.
Pokud tvuj kod vypada tak, jak jsi ho poslal, tak si s nim interpreter neporadi.
Zkus vlozit svuj kod jako kod. Druhe tlacitko zleva.

 
Odpovedať
23.9.2019 17:14
Tento výukový obsah pomáhajú rozvíjať nasledujúce firmy, ktoré možno hľadajú práve teba!
Avatar
josef rajmon
Člen
Avatar
Odpovedá na hanpari
josef rajmon:23.9.2019 17:47

je to ten samí kod co nahoře jen mi to vzdy vyhodí tabulku s tou chybou a označí tohle a radek nad tím: kostka = Kostka()

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()
 
Odpovedať
23.9.2019 17:47
Avatar
hanpari
Redaktor
Avatar
Odpovedá na josef rajmon
hanpari:24.9.2019 8:01
class Kostka:
    """
    Třída reprezentuje hrací kostku.
    """

    def __init__(self):
        self.__pocet_sten = 6

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


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

Chyba je v celém odsazení metody vrat_pocet_sten

A ano, v článku je chyba.

 
Odpovedať
24.9.2019 8:01
Avatar
josef rajmon
Člen
Avatar
Odpovedá na hanpari
josef rajmon:24.9.2019 10:50

Aha dekuji moc

 
Odpovedať
24.9.2019 10:50
Avatar
skamos
Člen
Avatar
skamos:19.10.2019 15:48

Ahoj. Proč se píše

return str("Kostka s {0} stěnami".format(self.__pocet_sten))

když

return "Kostka s {0} stěnami".format(self.__pocet_sten)

vrátí stejný výsledek? Proč je použita metoda str , chápu, že to pak vrátí string, ale to snad i bez té metody, alespoň v tomhle případě.

Editované 19.10.2019 15:50
 
Odpovedať
19.10.2019 15:48
Avatar
Marty
Člen
Avatar
Marty:16. marca 5:25

Modul si naimportujeme vnitřně (použijeme jedno podtržítko).
Při importování modulů se Python podívá, jestli byl již modul importován, takže pokud modul importoval dříve, tak ho Python znovu neimportuje.

Stále nechápu, proč tam je to začáteční podtržítko. Nejde to bez vytváření aliasu _random?

Díky.

 
Odpovedať
16. marca 5:25
Robíme čo je v našich silách, aby bola tunajšia diskusia čo najkvalitnejšia. Preto do nej tiež môžu prispievať len registrovaní členovia. Pre zapojenie sa do diskusie sa zaloguj. Ak ešte nemáš účet, zaregistruj sa, je to zadarmo.

Zatiaľ nikto nevložil komentár - buď prvý!