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

12. diel - Vlastnosti v Pythone

V minulej lekcii, Knižnica datetime pre Python , sme si vysvetlili dátum a čas. V dnešnom Python tutoriálu sa pozrieme na ďalšie prvky tried, ktoré ešte nepoznáme. Začnime prisľúbeným vlastnosťami.

Vlastnosti

Veľmi často sa nám stáva, že chceme mať kontrolu nad zmenami nejakého atribútu objektu zvonku. Budeme chcieť atribút nastaviť ako read-only alebo reagovať na jeho zmeny. Založme si súbor (názov Vlastnosti) a vytvorme nasledujúce triedu Študent, ktorá bude reprezentovať študenta v nejakom informačnom systéme.

class Student:
    def __init__(self, jmeno, pohlavi, vek):
        self.jmeno = jmeno
        self.muz = pohlavi
        self.vek = vek
        self.plnolety = (vek > 18)

    def __str__(self):
        jsem_plnolety = "jsem" if self.plnolety else "nejsem"
        pohlavi = "muž" if self.muz else "žena"
        return "Jsem {0}, {1}. Je mi {2} let a {3} plnoletý.".format(
            self.jmeno, pohlavi, self.vek, jsem_plnolety)

Trieda je veľmi jednoduchá, študent sa nejako volá, je nejakého pohlavia a má určitý vek. Podľa tohto veku sa nastavuje atribút plnoletý pre pohodlnejšie vyhodnocovanie plnoletosti na rôznych miestach systému. Na uloženie pohlavia používame boolean, či je študent muž. Konštruktor podľa veku určí, či je študent plnoletý. Metóda __str __ () je navrhnutá pre potreby tutoriálu tak, aby nám vypísala všetky informácie. V reáli by tam bolo pravdepodobne len meno študenta. Pomocou konstruktoru si nejakého študenta vytvorme:

s = Student("Pavel Hora", True, 20)
print(s)
input()

výstup:

Jsem Pavel Hora, muž. Je mi 20 let a jsem plnoletý.

Všetko vyzerá pekne, ale atribúty sú prístupné ako na čítanie, tak na zápis. Objekt teda môžeme rozbiť napríklad takto (hovoríme o nekonzistentnom vnútorným stave):

s = Student("Pavel Hora", True, 20)
s.vek = 15
s.muz = False
print(s)
input()

výstup:

Vlastnosti – teda Getter a setter Pythone - Objektovo orientované programovanie v Pythone

Určite musíme ošetriť, aby sa plnoletosť obnovila pri zmene veku. Keď sa zamyslíme nad ostatnými atribúty, nie je najmenší dôvod, aby sme ich taktiež umožňovali modifikovať. Študent si za normálnych okolností asi len ťažko zmení pohlavia alebo meno. Bolo by však zároveň vhodné ich vystaviť na čítanie, nemôžeme je teda iba iba nastaviť ako private. V skorších dieloch seriálu sme na tento účel používali metódy, ktoré slúžili na čítanie privátnych atribútov. Ich názov sme volili ako vrat_vek () a podobne. Na čítanie vybraných atribútov vytvoríme tiež metódy a atribúty označíme ako privátne. Trieda by novo vyzerala napr. Nasledovne:

class Student:

    def __init__(self, jmeno, pohlavi, vek):
        self.__jmeno = jmeno
        self.__muz = pohlavi
        self.__vek = vek
        self.__plnolety = (vek > 18)

    def __str__(self):
        jsem_plnolety = "jsem" if self.__plnolety else "nejsem"
        pohlavi = "muž" if self.__muz else "žena"
        return "Jsem {0}, {1}. Je mi {2} let a {3} plnoletý.".format(
            self.__jmeno, pohlavi, self.__vek, jsem_plnolety)

    def vrat_jmeno(self):
        return self.__jmeno

    def vrat_plnoletost(self):
        return self.__plnoletost

    def vrat_vek(self):
        return self.__vek

    def muz(self):
        return self.__muz

    def nastav_vek(self, hodnota):
        self.__vek = hodnota
        self.__plnolety = True
        if vek < 18:
            self.__plnolety = False

Metódy, čo hodnoty len vracajú, sú veľmi jednoduché. Nastavenie veku má už nejakú vnútornú logiku, pri jeho zmene musíme totiž prehodnotiť atribút plnoletá. Zaistili sme, že sa do premenných nedá zapisovať inak, ako my chceme. Máme teda pod kontrolou všetky zmeny atribútov a dokážeme na ne reagovať. Nemôže sa stať, že by nám niekto vnútorný stav nekontrolovane menil a rozbil.

Metódam na vrátenie hodnoty sa hovorí Getter a metódam pre zápis setter. Ručné písanie Getter a setter je určite veľmi zdĺhavé. Nemohol by sme si ušetriť prácu? Áno, v Pythone možno použiť kratšie a lepší zápis. Potom už nehovoríme o atribútoch, ale o vlastnostiach.

Syntax vlastnosti je veľmi podobná metóde:

@property
def jmeno(self):
    return self.__jmeno # atribut svázaný s metodou

Vytvoríme metódu, ktorá má rovnaký názov ako požadovaný názov vlastnosti. V tele metódy vrátime atribút spojený s vlastnosťou. Metódu dekorujeme dekorátorem property. Tým sa z metódy stane vlastnosť. Dekorátory majú nasledujúcu syntax:

@jmeno_dekoratoru
def nejaka_metoda(self):
    ...

V skutočnosti sú dekorátory objekty podporujúce volania (napr. Funkcie, metódy alebo objekty s metódou __call __ ()), ktoré vracia upravenú (dekorovanou) verziu metódy alebo funkcie. Preto možno použiť aj nasledujúcu syntax:

puvodni_nazev_metody = jmeno_dekoratoru()

V Pythone máme privátny atribút ak nemu máme dve metódy, ktoré podľa kontextu Python volá (spozná podľa situácie, či čítame alebo zapisujeme). Keď do vlastnosti nepridáme metódu pre setter, nepôjde meniť zvnútra ani zvonku. Vlastnosť sa potom používa podobne ako normálny atribút:

print(objekt.nazev_vlastnosti) # čtení
objekt.nazev_vlastnosti = hodnota # zápis

Ak si prajeme, aby sa vlastnosť vedela aj zapisovať, než len čítať, musíme si dodefinovať aj setter. Ukážme si to na našom príklade s dosiahnutím plnoletosti, ktorá sa musí po zmene veku prehodnotiť:

...
@property
def vek(self):
    return self.__vek

@vek.setter
def vek(self, hodnota):
    self.__vek = hodnota
    self.__plnolety = (hodnota > 18)

Sprvu je nutné si vytvoriť privátne premennú __vek, v ktorej bude hodnota v skutočnosti uložené. V Setter použijeme ďalší parameter, do ktorého sa uloží hodnota pre priradenie. S spevokol teraz pracujeme opäť rovnako, ako s atribútom. Nenápadné priradenie do veku vnútorne spustí ďalšiu logiku k prehodnoteniu atribútu plnoletá:

s.vek = 15 # nyní se změní i plnoletost

Rovnako môžeme pochopiteľne implementovať aj vlastné getter a napríklad niečo niekam logovať:

@nazev_vlastnosti.getter
def nazev_vlastnosti(self):
    return soukromy_atribut_vlastnosti

Ak chceme, aby sa getter správal inak, tak si telo metódy upravíme. Ovšem getter musí stále niečo vracať, inak by to nebol getter. :)

V Pythone sa vlastnosti používajú, iba len pokiaľ sú nutné. Celý program si samozrejme môžete stiahnuť pod článkom.

__dict__ a __slots__

Ak robíme vlastnosti, tak môžeme použiť ako "skládka" atribútu buď privátne atribút (pozri vyššie), alebo verejný atribút. Pokiaľ ale použijeme verejný atribút, tak sa nám prekryjú názvy atribútu a metódy vlastnosti a program upadne do rekurzia. Ide to ale obísť. Všetky atribúty objektov sa uchovávajú v slovníku spojenom s objektom. Dostaneme sa k nemu takto:

nazev_objektu.__dict__

Potom môžeme čítať / priradiť hodnotu bez rekurzia:

nazev_objektu.__dict__["nazev_promenne"] # čtení
nazev_objektu.__dict__["nazev_promenne"] = hodnota # zápis

Ak však nemáme pádny dôvod, aby bol atribút vlastnosti verejný, tak je to zbytočné. Navyše je tu jedno úskalia. Takto je možné meniť hodnoty iz vonka, bez toho, aby nám prešli kontrolou. Ošetriť to môžeme pomocou __slots__, čo by sa však nemalo vôbec použiť. Podľa dokumentácie Pythone by sme mali použiť __slots__ maximálne ak vytvárame veľké množstvo inštancií nejaké triedy a chceme za každú cenu ušetriť pamäť.

Napriek tomu sa dá k súkromným atribútom preniknúť za pomoci komolenie mien - k atribútu sa dostaneme za pomoci nasledujúcej syntaxe:

objekt.__NazevTridy_nazevatributu

Ale toto už určite nie je nevedomé získanie / zmenenie súkromného atribútu. :) V budúcej lekcii, Kvíz - Dedičnosť a polymorfizmus v Pythone , sa pozrieme na magické metódy objektov.

V nasledujúcom kvíze, Kvíz - Dedičnosť a polymorfizmus v Pythone, si vyskúšame nadobudnuté skúsenosti z predchádzajúcich lekcií.


 

Predchádzajúci článok
Knižnica datetime pre Python
Všetky články v sekcii
Objektovo orientované programovanie v Pythone
Preskočiť článok
(neodporúčame)
Kvíz - Dedičnosť a polymorfizmus v Pythone
Článok pre vás napísal gcx11
Avatar
Užívateľské hodnotenie:
1 hlasov
(^_^)
Aktivity