IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
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í.

9. diel - Statika v Pythone

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

V minulej lekcii, Riešené úlohy k 5.-8. lekciu OOP v Pythone , sme si v praxi vyskúšali dedičnosť a polymorfizmus. Dnes sa v Python tutoriálu budeme venovať pojmu statika. Až doteraz sme boli zvyknutí, že dáta (stav) nesie inštancie. Premenné, ktoré sme definovali, teda patrili inštanciu a boli pre každú inštanciu jedinečné. OOP však umožňuje definovať premenné a metódy na samotnej triede. Týmto prvkom hovoríme statické (alebo triedu) a sú nezávislé na inštanciu.

Pozor na statiku - Objektovo orientované programovanie v Pythone
POZOR! Dnešné lekcie vám ukáže statiku, teda postupy, ktoré v podstate narušujú objektový model. OOP je obsahuje len pre špeciálne prípady a všeobecne platí, že všetko ide napísať bez statiky. Vždy musíme starostlivo zvážiť, či statiku naozaj nutne potrebujeme. Všeobecne by som odporúčal statiku vôbec nepoužívať, ak si nie ste úplne istí, čo robíte. Podobne, ako globálne premenné je statika v objektovom programovaní niečo, čo umožňuje písať zlý kód a porušovať dobré praktiky. Dnes si ju teda skôr vysvetlíme. Znalosti použite s rozvahou, na svete bude potom menej zla.

Triedne premenné

Ako triedny môžeme označiť rôzne prvky. Začnime u premenných. Ako som sa už v úvode spomenul, statické prvky patrí triede, nie inštanciu. Dáta v nich uložené teda môžeme čítať bez ohľadu na to, či nejaká inštancia existuje. V podstate môžeme povedať, že triedna premenné sú spoločné pre všetky inštancie triedy, ale nie je to presné, pretože s inštanciami naozaj vôbec nesúvisí. Založme si nový súbor (názov napr. Statika) a urobme si jednoduchú triedu Uzivatel:

class Uzivatel:

    def __init__(self, jmeno, heslo):
        self.jmeno = jmeno
        self.heslo = heslo
        self.prihlaseny = False

    def prihlas_se(self, zadane_heslo):
        if self.heslo == zadane_heslo:
            self.prihlaseny = True
            return True
        else:
        self.prihlaseny = False
            return False # hesla nesouhlasí

Trieda je pomerne jednoduchá, reprezentuje používateľa nejakého systému. Každá inštancia používateľa má svoje meno, heslo a tiež sa o ňu vie, či je prihlásená alebo nie. Aby sa používateľ prihlásil, zavolá sa na ňom metóda prihlas_se () a v jej parametra heslo, ktoré človek za klávesnicou zadal. Metóda overí, či ide naozaj o tohto používateľa a pokúsi sa ho prihlásiť. Vráti True / False podľa toho, či prihlásenie prebehlo úspešne. V reáli by sa Vaše heslo ešte tzv. Hashovalo, ale to tu vynecháme.

Keď sa používateľ registruje, systém mu napíše, akú minimálnu dĺžku musí jeho heslo mať. Toto číslo by sme mali mať niekde uložené. Vo chvíli, keď používateľa registrujeme, tak ešte nemáme k dispozícii jeho inštanciu. Objekt nie je vytvorený a vytvoria sa až po vyplnení formulára. Samozrejme by bolo veľmi prínosné, keby sme mali údaj o minimálnej dĺžke hesla uložený v triede Uzivatel, pretože k nemu logicky patrí. Údaj uložíme do triednej premennej v triede Uzivatel za pomoci premenné minimalni_del­ka_hesla:

class Uzivatel:

    minimalni_delka_hesla = 6

    ...

Skúsme si premennú vypísať. K premenné teraz pristúpime priamo cez triedu:

print(Uzivatel.minimalni_delka_hesla)

Vidíme, že premenná naozaj patrí triede. Môžeme sa na ňu pýtať v rôznych miestach programu bez toho, aby sme mali používateľa vytvoreného. Avšak na inštanciu užívateľa túto premennú nájdeme tiež:

u = Uzivatel("Tomáš Marný", "heslojeveslo")
print(u.minimalni_delka_hesla)

Pozor! Pri zmene triedne premenné cez inštanciu zmeníme iba hodnotu pre danú inštanciu.

>>> class Trida:
        promenna = 1
>>> objekt = Trida()
>>> objekt.promenna = 2
>>> Trida.promenna
1

Ako ďalšie praktické využitie triednych premenných sa ponúka číslovanie používateľov. Budeme chcieť, aby mal každý užívateľ pridelené unikátne identifikačné číslo. Bez znalosti statiky by sme si museli strážiť zvonku každej vytvorenie užívateľa a počítať je. My si však môžeme vytvoriť priamo na triede Uzivatel privátne statickú premennú dalsi_id, kde bude vždy pripravené číslo pre ďalšieho užívateľa. Prvý užívateľ bude mať id 1, druhý 2 a tak ďalej. Používateľovi teda pribudne nový atribút id, ktorý sa v konstruktoru nastaví podľa hodnoty dalsi_id. Poďme si to vyskúšať:

class Uzivatel:
    minimalni_delka_hesla = 6
    dalsi_id = 1

    def __init__(self, jmeno, heslo):
        self.jmeno = jmeno
    self.heslo = heslo
    self.prihlaseny = False
        self.id = Uzivatel.dalsi_id
    Uzivatel.dalsi_id += 1

    ...

Trieda si sama ukladá, aké bude id ďalší jej inštancie. Toto id priradíme nové inštanciu v konstruktoru a zvýšime ho o 1, aby bolo pripravené pre ďalšiu inštanciu. Statické však nemusí byť len premenné, možnosti sú oveľa väčšie.

Statickej metódy

Statické metódy sa volajú na triede. Ide najmä o pomocné metódy, ktoré potrebujeme často používať a neoplatí sa nám tvoriť inštanciu.

Ukážme si opäť reálny príklad. Pri registrácii používateľa potrebujeme poznať minimálnu dĺžku hesla ešte pred jeho vytvorením. Bolo by tiež dobré, keby sme mohli pred jeho vytvorením aj heslo skontrolovať, či má správnu dĺžku, neobsahuje diakritiku, je v ňom aspoň jedno číslo a podobne. Na tento účel si vytvoríme pomocnú statickú metódu ZvalidujHeslo ():

@staticmethod
def zvaliduj_heslo(heslo):
    if len(heslo) >= Uzivatel.minimalni_delka_hesla:
        return True
    else:
        return False

Opäť si skúsime, že metódu môžeme na triede Uzivatel zavolať:

print(Uzivatel.zvaliduj_heslo("heslojeveslo"));

Pozor! Vďaka tomu, že je metóda zvaliduj_heslo () statická, nemôžeme v nej pristupovať k žiadnym inštančným premenným. Tieto premenné totiž neexistujú v kontexte triedy, ale inštancie. Pýtať sa na meno by v našej metóde nemalo zmysel! Môžete si skúsiť, že to naozaj nejde.

Python obsahuje okrem, statických aj triedne metódy. Táto metódy navyše dostávajú ako prvý parameter triedu. Triedny metódy sa hodí v tom prípade, že budeme triedu dediť a chceme mať v potomkovi inú hodnotu triednej premennej. Inak je lepšie použiť statickú metódu.

@classmethod
def zvaliduj_heslo(cls, heslo):
    if len(heslo) >= cls.__minimalni_delka_hesla:
        return True
    else:
        return False

Prvý parameter obsahujúce odkaz na triedu sa podľa konvencií pomenúva cls. Za pomoci tohto parametra potom voláme triedny premenné, podobne ako sa self.

Rovnaké funkčnosti pri validácii heslá samozrejme môžeme dosiahnuť aj bez znalosti statiky. Vytvorili by sme si nejakú triedu, napr. ValidatorUzivatelu a do nej napísali tieto metódy. Museli by sme potom vytvoriť jej inštanciu, aby sme metódy mohli volať. Bolo by to trochu mätúce, pretože logika užívateľa by bola zbytočne rozdelená do dvoch tried, keď môže byť za pomoci statiky pohromade.

U príklade sa statickou premennou minimalni_del­ka_hesla sme porušili zapuzdrenie, nemali by sme dovoľovať premennú nekontrolovane meniť. Môžeme ju samozrejme nastaviť ako privátne ak jej čítaní vytvoriť statickú metódu. To ostatne dobre poznáme z minulých dielov. Doplníme takú metódu ik navrátenie id a vyskúšame si ešte nakoniec naše metódy. Koniec programu bude vyzerať takto:

u = Uzivatel("Tomáš Marný", "heslojeveslo")
print("ID prvního uživatele je:", u.vrat_id())
v = Uzivatel("Olí Znusinudle", "csfd1fg")
print("ID druhého uživatele je:", v.vrat_id())
print("Minimální délka hesla uživatele je:",
      Uzivatel.vrat_minimalni_delku_hesla())
print('Validnost hesla "heslo" je:',
      Uzivatel.zvaliduj_heslo("heslo"))
input()

A výstup bude:

Statické, triedne metódy a atribúty v Pythone - Objektovo orientované programovanie v Pythone

Od Pythone 3 možno navyše zlučovať "obyčajné funkcie" do tried. Napríklad môžeme použiť:

class Trida:

    def nejaka_funkce():
    print("Tahle funkce je ve třídě.")

    def jina_funkce(text):
        print("Tahle funkce je také ve třídě!")
    print("Text je:", text)
Trida.nejaka_funkce()
Trida.jina_funkce("parametr")

Vyzerá to podobne, ako by boli funkcie obsiahnuté v nejakom module.

Dodatok k priloženému kódu

Do zdrojového kódu som pre zjednodušenie pridal tieto riadky:

vrat_minimalni_delku_hesla = vrat_minimalni_delku_hesla_s
zvaliduj_heslo = zvaliduj_heslo_s

Vytvorí sa nové objekty (funkcie), ktorý sa "zviažu" s pôvodnými funkciami. To nám umožní funkcie použiť bez dodatočného používania písmen na rozlišovanie medzi statickými a triednymi verziami funkcií. Môžete si skúsiť, že obe funkcie odkazujú na rovnaký objekt pomocou operátora is.

Statika sa veľmi často vyskytuje v návrhových vzoroch, o ktorých sme sa tu už bavili. Sú to postupy, ktoré dovádza objektovo orientované programovanie k dokonalosti ao ktorých sa tu určite ešte zmienime. Pre dnešok je toho však už dosť :) V budúcej lekcii, Riešené úlohy k 9. lekcii OOP v Pythone , sa pozrieme na dátum a čas v Pythone.

V nasledujúcom cvičení, Riešené úlohy k 9. lekcii OOP v Pythone, si precvičíme 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é 548x (941 B)
Aplikácia je vrátane zdrojových kódov v jazyku Python

 

Predchádzajúci článok
Riešené úlohy k 5.-8. 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 9. lekcii OOP v Pythone
Článok pre vás napísal gcx11
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
(^_^)
Aktivity