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

Lekce 3 - Hrací kostka v Pythonu - Zapouzdření a konstruktor

V předešlém cvičení, Řešené úlohy k 1.-2. lekci OOP v Pythonu, jsme si procvičili nabyté zkušenosti z předchozích lekcí.

V tomto tutoriálu objektově orientovaného programování v Pythonu začneme pracovat na slíbené aréně, ve které budou proti sobě bojovat dva bojovníci. Boj bude tahový (na přeskáčku) a bojovník vždy druhému ubere život na základě síly jeho útoku a obrany druhého bojovníka. Simulujeme v podstatě stolní hru a budeme tedy simulovat i hrací kostku, která dodá hře prvek náhodnosti. Začněme zvolna a vytvořme si dnes právě tuto hrací kostku. Zároveň se naučíme jak definovat vlastní konstruktor.

Vytvoření projektu

Vytvoříme si nový projekt a pojmenujeme ho TahovyBoj. V projektu vytvoříme nový soubor kostka.py a v něm třídu s názvem Kostka. Zamysleme se nad atributy, které kostce dáme. Jistě by se hodilo, kdybychom si mohli zvolit počet stěn kostky (klasicky 6 nebo 10 stěn, jak je zvykem u tohoto typu her). Naše třída proto bude mít atribut pocet_sten.

Minule jsme kvůli jednoduchosti nastavovali všechny atributy naší třídy jako veřejně přístupné. Většinou se však spíše nechce, aby se daly zvenčí modifikovat. Proto se nastavují jako soukromé. Soukromé atributy začínají jedním nebo dvěma podtržítky. Jedním podtržítkem není přístup odepřen, ale dáváme najevo, že daný prvek se nemá z vnější používat. Dvě podtržítka způsobí, že k atributu poté nelze normálně přistupovat.

My budeme v kurzu používat jedno podtržítko.

Při návrhu třídy tedy použijeme pro atributy podtržítka. Nepoužijeme je pouze v případě, že něco bude opravdu potřeba vystavit. Naše třída nyní vypadá takto:

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

Konstruktory

Až doposud jsme neuměli zvenčí nastavit jiné atributy než veřejné, protože soukromé atributy nejsou zvenčí viditelné. Již jsme si říkali něco málo o konstruktoru objektu. Je to metoda, která se zavolá ve chvíli vytvoření instance objektu. Slouží k nastavení vnitřního stavu objektu a k provedení případné inicializace. Kostku nyní vytvoříme takto:

kostka = Kostka()

Právě Kostka() je konstruktor. Protože v naší třídě žádný není, Python si sám vygeneruje prázdnou metodu. My si však nyní konstruktor do třídy přidáme. Deklaruje se jako metoda. V Pythonu můžeme použít metody hned dvě. Metodu __new__() a metodu __init__(). Ta první se volá při vytváření objektu, ale většinou si vystačíme se druhou metodu, která se volá při inicializaci objektu.

Popis rozdílu mezi oběma metodami vyžaduje výrazně hlubší znalosti principů OOP, než kterými zatím disponujeme. Většina programátorů v Pythonu nikdy nepotřebuje přepsat metodu __new__(). Drtivá většina tříd potřebuje pouze __init__() k nastavení počátečního stavu objektu. Pokud si tedy nejsme odůvodněně jistí, zda potřebujeme __new__(), tak ji nepotřebujeme :-)

Vraťme se tedy k metodě __init__(). Jako první parametr píšeme self. Pokud v metodě __init__() jen tak vytvoříme nějakou proměnnou, tak ta po ukončení metody zaniká. My ale potřebujeme vytvořit atribut pocet_sten, který chceme dále používat. Atributy objektů se vytvářejí všemocným slůvkem self. Za self následuje tečka a název atributu. Vytvoříme tedy veřejný atribut pocet_sten:

def __init__(self):
    self.pocet_sten = 6

Pokud kostku nyní vytvoříme, bude atribut pocet_sten nastaven na 6. Vypišme si počet stěn do konzole, ať vidíme, že tam hodnota opravdu je:

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

    def __init__(self):
        self.pocet_sten = 6


kostka = Kostka()
print(kostka.pocet_sten)

V konzoli vidíme výstup:

Atribut pocet_sten:
6

Zapouzdření

Není dobré atribut pocet_sten nastavit jako veřejný, protože nechceme, aby nám někdo mohl již u vytvořené kostky počet stěn měnit. Přidáme do třídy tedy metodu vrat_pocet_sten(), která nám vrátí hodnotu atributu pocet_sten a tento atribut upravíme na neveřejný pomocí podtržítka. Docílíme tím v podstatě toho, že je atribut označený jako read-only (atribut bychom měli pouze číst metodou). Aby byl skutečně read-only a zvenčí nepřístupný, museli bychom podtržítka použít dvě, ale tím se zatím nebudeme zabývat. Upravená verze třídy i s metodou:

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

    def __init__(self):
        self._pocet_sten = 6      # jedno podtržítko dává najevo, že nechceme, aby se k atributu přistupovalo přímo

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


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

V konzoli vidíme výstup:

Výstup metody vrat_pocet_sten():
6

Atribut se stal neveřejným díky přidání podtržítka. Navíc jsme změnili vypisování, jelikož hodnotu atributu zjistíme pouze zavoláním metody.

Volitelný počet stěn

Vidíme, že se konstruktor opravdu zavolal. My bychom ale chtěli, abychom mohli u každé kostky při vytvoření specifikovat, kolik stěn budeme potřebovat. Dáme tedy konstruktoru parametr:

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

Vidíme, že názvy atributu a argumentu jsou skoro stejné. Pokud bychom měli počet stěn jako veřejný atribut, stejný název nevadí. Pomocí self specifikujeme, že levá proměnná pocet_sten náleží instanci, pravou Python chápe jako předanou z parametru (argumentu). S veřejným atributem by situace vypadala takto:

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

Vraťme se však k původnímu kódu a zkusme si zadat parametr do konstruktoru:

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

V konzoli vidíme výstup:

Výstup s parametrem konstruktoru 10:
10

Výchozí hodnota kostky

Vše funguje, jak jsme očekávali. Python nám již v tuto chvíli nevygeneruje prázdný (tzv. bezparametrický) konstruktor, takže kostku bez parametru již vytvořit nelze. My to však můžeme umožnit pomocí uvedení výchozí hodnoty argumentu pocet_sten v definici konstruktoru. Nastavíme ji na hodnotu 6. Takovou hodnotu uživatel naší třídy u kostky očekává jako výchozí:

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

Vytvořme teď dvě instance kostky, jednu bez udání počtu stěn a jednu s ním:

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

Máme tedy konstruktor, který nám umožňuje tvořit různé hrací kostky. Díky klíčovému argumentu nemusíme zadávat počet stěn.

Toho můžeme využívat i u všech dalších metod, nejen u konstruktorů. Mnoho funkcí a metod v Pythonu má klíčové argumenty, například vestavěná funkce print(). Je dobré si u metod projít jejich klíčové argumenty, abychom neprogramovali něco, co již někdo udělal před námi.

To je pro dnešní lekci vše.

V příští lekci, Hrací kostka v Pythonu podruhé - Překrývání metod a random, se naučíme překrývat metody, používat vnitřní import a dokončíme hrací kostku.


 

Měl jsi s čímkoli problém? Zdrojový kód vzorové aplikace je ke stažení každých pár lekcí. Zatím pokračuj dál, a pak si svou aplikaci porovnej se vzorem a snadno oprav.

Předchozí článek
Řešené úlohy k 1.-2. lekci OOP v Pythonu
Všechny články v sekci
Objektově orientované programování v Pythonu
Přeskočit článek
(nedoporučujeme)
Hrací kostka v Pythonu podruhé - Překrývání metod a random
Článek pro vás napsal gcx11
Avatar
Uživatelské hodnocení:
509 hlasů
(^_^)
Aktivity