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

3. diel - Hracia kocka v Pythone - Zapuzdrenie a konštruktor

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 tomto tutoriáli objektovo orientovaného programovania v Pythone začneme pracovať na sľúbenej 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 a 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.

Vytvorenie projektu

Vytvoríme si nový projekt a pomenujeme ho ArenaFight. V projekte vytvoríme nový súbor rolling_die.py a v ňom triedu s názvom RollingDie. Zamyslime sa nad atribútmi, 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 pri tomto type hier). Naša trieda preto bude mať atribút sides_count.

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ť. Preto sa nastavujú ako súkromné. Súkromné atribúty začínajú jedným alebo dvoma podčiarkovníkmi. Jedným podčiarkovníkom nie je prístup odmietnutý, ale dávame najavo, že daný prvok sa nemá z vonkajšej používať. Dve podčiarkovníky spôsobia, že k atribútu potom nemožno normálne pristupovať.

My budeme v kurze používať jedno podčiarknutie.

Pri návrhu triedy teda použijeme pre atribúty podčiarkovníka. Nepoužijeme ich iba v prípade, že niečo bude naozaj potrebné vystaviť. Naša trieda teraz vyzerá takto:

class RollingDie:
    """
    Class representing a die for a board game.
    """

Konštruktory

Až doteraz sme nevedeli zvonku nastaviť iné atribúty ako verejné, pretože súkromné atribúty nie sú zvonku viditeľné. Už sme si hovorili niečo málo o konštruktore objektu. Je to metóda, ktorá sa zavolá vo chvíli vytvorenia inštancie objektu. Slúži na nastavenie vnútorného stavu objektu a na vykonanie prípadnej inicializácie. Kocku teraz vytvoríme takto:

die = RollingDie()

Práve RollingDie() je konštruktor. Pretože v našej triede žiadny nie je, Python si sám vygeneruje 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 s druhou metódou, ktorá sa volá pri inicializácii objektu.

Popis rozdielu medzi oboma metódami vyžaduje výrazne hlbšie znalosti princípov OOP, než ktorými zatiaľ disponujeme. Väčšina programátorov v Pythone nikdy nepotrebuje prepísať metódu __new__(). Drvivá väčšina tried potrebuje iba __init__() na nastavenie počiatočného stavu objektu. Pokiaľ si teda nie sme odôvodnene istí, či potrebujeme __new__(), tak ju nepotrebujeme :-)

Vráťme sa teda k metóde __init__(). Ako prvý parameter píšeme self. Pokiaľ v metóde __init__() len tak vytvoríme nejakú premennú, tak tá po ukončení metódy zaniká. My ale potrebujeme vytvoriť atribút sides_count, ktorý chceme ďalej používať. Atribúty objektov sa vytvárajú všemocným slovíčkom self. Za self nasleduje bodka a názov atribútu. Vytvoríme teda verejný atribút sides_count:

def __init__(self):
    self.sides_count = 6

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

class RollingDie:
    """
    Class representing a die for a board game.
    """

    def __init__(self):
        self.sides_count = 6


die = RollingDie()
print(die.sides_count)

V konzole vidíme výstup:

Attribute sides_count:
6

Zapuzdrenie

Nie je dobré atribút sides_count nastaviť ako verejný, pretože nechceme, aby nám niekto mohol už pri vytvorenej kocke počet stien meniť. Pridáme do triedy teda metódu get_sides_count(), ktorá nám vráti hodnotu atribútu sides_count a tento atribút upravíme na neverejný pomocou podčiarkovníka. Docielime tým v podstate to, že je atribút označený ako read-only (atribút by sme mali iba čítať metódou). Aby bol skutočne read-only a zvonku neprístupný, museli by sme podčiarkovníky použiť dve, ale tým sa zatiaľ nebudeme zaoberať. Upravená verzia triedy aj s metódou:

class RollingDie:
    """
    Class representing a die for a board game.
    """

    def __init__(self):
        self._sides_count = 6      # A single underscore indicates that we do not want the attribute to be accessed directly.

    def get_sides_count(self):
        """
        Returns the number of sides the die has.
        """
        return self._sides_count


die = RollingDie()
print(die.get_sides_count())

V konzole vidíme výstup:

Output of the method get_sides_count():
6

Atribút sa stal neverejným vďaka pridaniu podčiarkovníka. Navyše sme zmenili vypisovanie, pretože hodnotu atribútu zistíme iba zavolaním metódy.

Voliteľný počet stien

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

def __init__(self, sides_count):
    self._sides_count = sides_count

Vidíme, že názvy atribútu a argumentu sú skoro rovnaké. Pokiaľ by sme mali počet stien ako verejný atribút, rovnaký názov nevadí. Pomocou self špecifikujeme, že ľavá premenná sides_count patrí inštancii, pravú Python chápe ako odovzdanú z parametra (argumentu). S verejným atribútom by situácia vyzerala takto:

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

Vráťme sa však k pôvodnému kódu a skúsme si zadať parameter do konštruktora:

die = RollingDie(10) # a constructor with a par. 10 is called
print(die.get_sides_count())

V konzole vidíme výstup:

Output with constructor parameter 10:
10

Východisková hodnota kocky

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ť nemožno. My to však môžeme umožniť pomocou uvedenia východiskovej hodnoty argumentu sides_count v definícii konštruktora. Nastavíme ju na hodnotu 6. Takúto hodnotu užívateľ našej triedy u kocky očakáva ako východiskovú:

def __init__(self, sides_count=6):
    self._sides_count = sides_count

Vytvorme teraz dve inštancie kocky, jednu bez udania počtu stien a jednu s ním:

sixSided = RollingDie()
tenSided = RollingDie(10) # or we can write RollingDie(sides_count=10)
print(sixSided.get_sides_count())
print(tenSided.get_sides_count())

Máme teda konštruktor, ktorý nám umožňuje tvoriť rôzne hracie kocky. Vďaka kľúčovému argumentu nemusíme zadávať počet stien.

To môžeme využívať aj pri všetkých ďalších metódach, nielen pri konštruktoroch. Veľa funkcií a metód v Pythone má kľúčové argumenty, napríklad vstavaná funkcia print(). Je dobré si pri metódach prejsť ich kľúčové argumenty, aby sme neprogramovali niečo, čo už niekto urobil pred nami.

To je pre dnešnú lekciu všetko.

V budúcej lekcii, Hracia kocka v Pythone - Prekrývanie metód a random, sa naučíme prekrývať metódy, používať vnútorný import a dokončíme hraciu kocku.


 

Mal si s čímkoľvek problém? Zdrojový kód vzorovej aplikácie je k stiahnutiu každých pár lekcií. Zatiaľ pokračuj ďalej, a potom si svoju aplikáciu porovnaj so vzorom a ľahko opráv.

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)
Hracia kocka v Pythone - Prekrývanie metód a random
Článok pre vás napísal gcx11
Avatar
Užívateľské hodnotenie:
5 hlasov
(^_^)
Aktivity