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

7. diel - Dedičnosť a polymorfizmus v Pythone

V predchádzajúcej lekcii, Kopírovanie objektov v Pythone , sme sa naučili spôsoby, ktorými je možné kopírovať objekty.

V minulej lekcii, Kopírovanie objektov v Pythone , sme dokončili našu arénu, simulujúce zápas dvoch bojovníkov. Dnes si opäť rozšírime znalosti o objektovo orientovanom programovaní. V úvodnej lekcii do OOP sme si hovorili, že OOP stojí na troch základných pilieroch: zapuzdrenie, dedičnosti a polymorfizmu. Zapuzdrenie a používanie podčiarkovníkov je už dobre známe. V dnešnom Python tutoriálu sa pozrieme na zvyšné dva piliere.

Dedičnosť

Dedičnosť je jedna zo základných vlastností OOP a slúži k tvoreniu nových dátových štruktúr na základe starých. Vysvetlime si to na jednoduchom príklade:

Budeme programovať informačný systém. To je celkom reálny príklad, aby sme si však učenie spríjemnili, bude to informačný systém pre správu zvierat v ZOO :) Náš systém budú používať dva typy užívateľov: užívateľ a administrátor. Užívateľ je bežný ošetrovateľ zvierat, ktorý bude môcť upravovať informácie o zvieratách, napr. Ich váhy alebo rozpätie krídel. Administrátor bude môcť tiež upravovať údaje o zvieratách a navyše zvieratá pridávať a mazať z databázy. Z atribútov bude mať navyše telefónne číslo, aby ho bolo možné kontaktovať v prípade výpadku systému. Bolo by určite zbytočné a neprehľadné, keby sme si museli definovať obe triedy úplne celé, pretože mnoho vlastností týchto 2 objektov je spoločných. Užívateľ aj administrátor budú mať určite meno, vek a budú sa môcť prihlásiť a odhlásiť. Nadefinujeme si teda iba triedu Uzivatel (nepôjde o funkčné ukážku, dnes to bude len teória, programovať budeme nabudúce):

class Uzivatel:

    def __init__(self, jmeno, heslo, vek):
        self.__jmeno = jmeno
        self.__heslo = heslo
        self.__vek = vek

    def prihlasit(self, heslo):
    ...

    def odhlasit(self):
    ...

    def nastav_vahu(self, zvire):
    ...

    ...

Triedu som len naznačil, ale iste si ju dokážeme dobre predstaviť. Bez znalosti dedičnosti by sme triedu Administrator definovali asi takto:

class Administrator:

    def __init__(self, jmeno, heslo, vek, telefonni_cislo):
    self.__jmeno = jmeno
    self.__heslo = heslo
    self.__vek = vek
    self.__telefonni_cislo = telefonni_cislo

    def prihlasit(self, heslo):
    ...

    def odhlasit(self):
    ...

    def nastav_vahu(self, zvire):
    ...

    def pridej_zvire(self, zvire):
    ...

    def vymaz_zvire(self, zvire):
    ...

    ...

Vidíme, že máme v triede veľa redundantného (duplikovaného) kódu. Akékoľvek zmeny musíme teraz vykonávať v oboch triedach, kód sa nám veľmi komplikuje. Teraz použijeme dedičnosť, definujeme teda triedu Administrator tak, aby z triedy Uzivatel dedila. Atribúty a metódy užívateľa teda už nemusíme znovu definovať, Python je sám do triedy dodá:

class Administrator(Uzivatel):

    def __init__(self, jmeno, heslo, vek, telefonni_cislo):
    super().__init__(jmeno, heslo, vek)
    self.__telefonni_cislo = telefonni_cislo

    def pridej_zvire(self, zvire):
    ...

    def vymaz_zvire(self, zvire):
    ...

    ...

Vidíme, že ku zdedenie používame zátvorky. Medzi zátvorky píšeme triedy, od ktorých naša trieda dedí. V anglickej literatúre nájdete dedičnosť pod slovom inheritance.

Toho "podivného" super () si zatiaľ nebudeme všímať - bude vysvetlené neskôr (ale je potrebné, ak chceme použiť metódu rodičia). Ale späť k príkladu.

V potomkovi nebudú prístupné privátne atribúty, ale iba verejné atribúty a metódy. Súkromné atribúty a metódy sú chápané ako špeciálne logika konkrétnej triedy, ktorá je potomkovi utajená, aj keď ju vlastne používa, nemôže ju meniť. Aby sme dosiahli požadovaného výsledku, použijeme nový modifikátor prístupu a to (nečakane) jedno znak podčiarknutia. V Pythone sa atribúty a metódy s jedným podčiarknikom nazývajú vnútorné. Pre ostatné programátorov, alebo objekty to znamená: "Toto je síce zvonku viditeľné, ale, prosím, nehrabejte mi na to!" Začiatok triedy Uzivatel by teda vyzeral takto:

class Uzivatel:

    def __init__(self, jmeno, heslo, vek):
        self._jmeno = jmeno
        self._heslo = heslo
        self._vek = vek

Keď si teraz vytvoríme inštanciu užívateľa a administrátora, obaja budú mať napr. Atribút jmeno a metódu prihlasit (). Python triedu Uzivatel zdedí a automaticky nám doplní všetky jej atribúty.

Výhody dedenie sú jasné, nemusíme opisovať obom triedam tie isté atribúty, ale stačí dopísať len to, v čom sa líšia. Zvyšok sa zdedí. Prínos je obrovský, môžeme rozširovať existujúce komponenty o nové metódy a tým je znovu využívať. Nemusíme písať hŕbu redundantného (duplikovaného) kódu. A hlavne - keď zmeníme jediný atribút v materskej triede, automaticky sa táto zmena všade zdedí. Nedôjde teda k tomu, že by sme to museli meniť ručne u 20tich tried a niekde na to zabudli a spôsobili chybu. Sme ľudia a chybovať budeme vždy, musíme teda používať také programátorské postupy, aby sme mali možnosť chybovať čo najmenej.

O materskej triede sa niekedy hovorí ako o predkovi (tu Uzivatel) ao triede, ktorá z nej dedí, ako o potomkovi (tu Administrator). Potomok môže pridávať nové metódy alebo si prispôsobovať metódy z materskej triedy (viď ďalej). Môžete sa stretnúť aj s pojmami nadtřída a podtrieda.

Ďalšou možnosťou, ako objektový model navrhnúť, by bolo zaviesť materskú triedu Uzivatel, ktorá by slúžila len k dedenie. Z Uzivatel by potom totiž dedili ošetrovateľ az neho Administrator. To by sa však oplatilo pri väčšom počte typov používateľov. V takomto prípade hovoríme o hierarchii tried, budeme sa tým zaoberať ku koncu tejto sekcie. Náš príklad bol jednoduchý a preto nám stačili iba 2 triedy. Existujú tzv. Návrhové vzory, ktoré obsahujú osvedčená schémy objektových štruktúr pre známe prípady použitia. Záujemcovia je nájdu popísané v sekcii Návrhové vzory, je to však už pokročilejšie problematika a tiež veľmi zaujímavá. V objektovom modelovania sa dedičnosť znázorňuje graficky ako prázdna šípka smerujúca k predkovi. V našom prípade by grafická notácie vyzerala takto:

Dedičnosť objektov – grafická notácie - Objektovo orientované programovanie v Pythone

Testovanie typu triedy

V Pythone môžeme testovať či je objekt inštanciou určitej triedy.

  1. Môžeme použiť zabudovanú funkciu type ():
>>> a = 1
>>> type(a) == type(1)
True
>>> type(a) == type("Python!")
False
>>> type(a) == int
True
>>> type(a) == str
False
  1. Ale lepšie je použiť zabudovanú funkciu isinstance ():
>>> a = 1
>>> isinstance(a, 1)
True
>>> isinstance(a, "Python")
False
>>> isinstance(a, int)
True
>>> isinstance(a, str)
False

Ďalej môžeme zistiť nadtřídu / nadtřídy objektu (triedy).

>>> a = 1
>>> a.__class__.__base__
<class 'object'>
>>> a.__class__.__bases__
(<class 'object'>,)

Všetky objekty v Pythone dedí z triedy objekt. V Pythone 2.X bolo nutné uvádzať, že nami vytvorená trieda dedí z triedy objekt. Teraz si to Python "doplní" sám.

Jazyky, ktoré dedičnosť podporujú, buď vie dedičnosť jednoduchú, kde trieda dedí len z jednej triedy, alebo viacnásobnú, kde trieda dedí hneď z niekoľkých tried naraz. Python podporuje viacnásobnú dedičnosť ako napr. C ++.

Polymorfizmus

Nenechajte sa vystrašiť príšerným názvom tejto techniky, pretože je v jadre veľmi jednoduchá. Polymorfizmus umožňuje používať jednotné rozhranie pre prácu s rôznymi typmi objektov. Majme napríklad veľa objektov, ktoré reprezentujú nejaké geometrické útvary (kruh, štvorec, trojuholník). Bolo by určite prínosné a prehľadné, keby sme s nimi mohli komunikovať jednotne, hoci sa líšia. Môžeme zaviesť triedu GeometrickyUtvar, ktorá by obsahovala atribút farba a metódu vykresli (). Všetky geometrické tvary by potom dedili z tejto triedy jej interface (rozhranie). Objekty kruh a štvorec sa ale iste vykresľujú inak. Polymorfizmus nám umožňuje prepísať si metódu vykresli () pri každej podtriedy tak, aby robila, čo chceme. Rozhranie tak zostane zachované a my nebudeme musieť premýšľať, ako sa to u onoho objekte volá.

Polymorfizmus býva často vysvetľovaný na obrázku so zvieratami, ktoré majú všetky v rozhraní metódu speak (), ale každé si ju vykonáva po svojom.

polymorfizmus - Objektovo orientované programovanie v Pythone

Podstatou polymorfizmu je teda metóda alebo metódy, ktoré majú všetci potomkovia definované s rovnakou hlavičkou, ale iným telom. Polymorfizmus si spolu s dedičnosťou vyskúšame v nasledujúcej lekcii, Aréna s mágom (dedičnosť a polymorfizmus) , na bojovníkoch v našej aréne. Pridáme mága, ktorý si bude metódu útočí () vykonávať po svojom pomocou many, ale inak zdedí správanie a atribúty bojovníka. Zvonku teda vôbec nespoznáme, že to nie je bojovník, pretože bude mať rovnaké rozhranie. Bude to zábava :)


 

Predchádzajúci článok
Kopírovanie objektov v Pythone
Všetky články v sekcii
Objektovo orientované programovanie v Pythone
Preskočiť článok
(neodporúčame)
Aréna s mágom (dedičnosť a polymorfizmus)
Článok pre vás napísal gcx11
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
(^_^)
Aktivity