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

18. diel - Vlastnosti v Pythone

V predchádzajúcej lekcii, Dekorátory druhýkrát - Parametrické a triedne dekorátory , sme dokončili tému s dekorátormi.

V dnešnom tutoriáli objektovo orientovaného programovania v Pythone sa pozrieme na ďalšie prvky tried, ktoré ešte nepoznáme. Zameriame sa na vlastnosti (properties). Ukážeme si, ako vďaka nim elegantne vyriešime nastavovanie a validáciu hodnôt atribútov.

Vlastnosti v Pythone

Vlastnosti nám ponúkajú elegantný a flexibilný spôsob, ako pracovať s atribútmi objektov. Vo svojej podstate nám umožňujú definovať metódy, ktoré vyzerajú a chovajú sa ako atribúty. Vďaka tomu máme pod kontrolou, čo sa stane, keď je atribút nastavený, čítaný, alebo dokonca mazaný, a to všetko s uchovaním rovnakého rozhrania ako pri obyčajných atribútoch. To je užitočné v kontexte zapuzdrenia dát a obmedzenia priameho prístupu k dátam objektu, hoci rozhodne nejde o absolútne riešenie. V mnohých iných jazykoch je zapuzdrenie implementované pomocou súkromných atribútov a verejných metód (getters a setters). My už tušíme, že Python má ako obvykle svoj vlastný špecifický prístup. Ponúka nám vlastnosti, ktoré tieto koncepty spájajú do jedného elegantného a čitateľného riešenia.

Dekorátor @property

Kľúčovým prvkom pre vytvorenie vlastnosti je dekorátor @property. Ak máme jednoduchý atribút, ktorý chceme upraviť tak, aby obsahoval validáciu alebo dodatočnú logiku pri čítaní, práve týmto dekorátorom ho premeníme na vlastnosť.

Majme napríklad triedu Person s atribútom age. Chceme zaistiť, že vek bude vždy kladné číslo. Preto tento atribút premeníme na vlastnosť a pridáme zodpovedajúcu validáciu:

class Person:
    def __init__(self, age):
        self._age = age          # private attribute age

    @property
    def age(self):
        return f"The age of the person is {self._age} years."

    @age.setter
    def age(self, value):
        if value < 0:
            print("Error! Age cannot be negative.")
        else:
            self._age = value

person = Person(10)
person.age = -20
print(person.age)

V tomto príklade je _age skrytý atribút, ktorý skutočne uchováva hodnotu veku. Verejná vlastnosť age (už bez podčiarkovníka) potom umožňuje čítať a nastavovať tento skrytý atribút, ale s možnosťou pridania ďalšej logiky, ako je validácia. Pokus o vloženie nesprávnej hodnoty do atribútu spôsobí vypísanie chybovej hlášky a zmena sa nevykoná.

Atribút je stále priamo dostupný aj zvonku, pokiaľ k nemu pristúpime zápisom person._age = -20. Pravidlá prístupu k atribútom zostávajú rovnaké, ako sme si ich ukázali v lekcii Zapúzdrenie atribútov podrobne.

Kombinácia @property a @attribute_name.setter je syntaktická povinnosť, nie iba konvencia. Zatiaľ čo @property bez setteru použiť je možné, pokus použiť setter bez @property spôsobí chybu. Pokiaľ použijeme iba @property (hovorí sa mu tiež getter), získame takzvanú read-only vlastnosť. To znamená, že hodnotu tejto vlastnosti možno získať (prečítať), ale nemôže byť priamo nastavená.

Pomocou @property, teda getteru, dáta čítame a pomocou @attribute_name.setter, teda setteru, dáta nastavujeme.

Kedy použiť vlastnosti namiesto metód

Vlastnosti v Pythone nám umožňujú kombinovať výhody metód a prístupu k atribútom. Ponúka sa otázka, kedy je vhodné vlastnosti použiť namiesto klasických metód. Pozrime sa na niekoľko situácií, kedy sú vlastnosti vhodnou voľbou:

  • prirodzený prístup k dátam – ak chceme, aby sa prístup k niektorým dátam triedy zdal byť ako k obyčajnému atribútu, ale potrebujeme viac kontroly nad tým, čo sa deje pri čítaní alebo zápise týchto dát,
  • zachovanie kompatibility – ak máme existujúcu triedu s verejným atribútom a chceme pridať nejakú logiku pri čítaní alebo zápise tohto atribútu, zmeníme ho na vlastnosť bez nutnosti meniť rozhranie triedy. To znamená, že existujúci kód, ktorý túto triedu využíva, bude fungovať bez zmien,
  • validácia dát – vlastnosti sú ideálne na implementáciu validácie dát.

Vzhľadom na princípy, na ktorých je Python postavený, vlastnosti neposkytujú z hľadiska zapuzdrenia príliš robustnú ochranu. Stále je našou zodpovednosťou vyvarovať sa priamym zásahom do súkromných alebo privátnych atribútov.

Pozrime sa na doterajší výklad formou komplexnejšieho príkladu. Predstavme si, že máme triedu Regulator, ktorá simuluje teplotný regulátor. Chceme, aby užívateľ mohol nastaviť požadovanú teplotu, ale zároveň chceme zaistiť, že táto teplota nebude príliš vysoká ani príliš nízka (napr. medzi 10 °C a 30 °C):

class Regulator:
    def __init__(self):
        self._temperature = 20  # default temperature

    @property
    def temperature(self):
        return f"The current temperature is set to {self._temperature} °C."

    @temperature.setter
    def temperature(self, new_temperature):
        if 10 <= new_temperature <= 30:
            self._temperature = new_temperature
        else:
            print(f"Error! The temperature {new_temperature} °C is outside the allowed range (10 °C - 30 °C).")

    def set_temperature_in_kelvin(self, temperature_k):
        temperature_c = temperature_k - 273.15
        if 10 <= temperature_c <= 30:
            self._temperature = temperature_c
            return f"The current temperature is set to {temperature_k} °K."
        else:
            return f"Error! The temperature {temperature_k} K is outside the allowed range in °C (10 °C - 30 °C)."

# Usage:
regulator = Regulator()
print(regulator.temperature)  # Displays: The current temperature is set to 20 °C.

regulator.temperature = 25
print(regulator.temperature)

regulator.temperature = 35    # Displays error, temperature remains at 25 °C
print(regulator.temperature)

print(regulator.set_temperature_in_kelvin(298.15))

V tomto rozšírenom príklade používateľ nastavuje teplotu v °C pomocou vlastnosti @temperature.setter, ale má tiež možnosť nastaviť teplotu v kelvinoch pomocou metódy set_temperature_in_kelvin(). V praxi to znamená , že ak existuje nejaká špecifická funkcia alebo spôsob manipulácie s dátami, ktoré sa často nepoužívajú alebo sú zložitejšie, je lepšie použiť tradičnú metódu.

Pokiaľ však chceme, aby sa niektoré často vykonávané akcie (napr. validácia) vykonávali automaticky pri čítaní alebo nastavovaní hodnoty, sú vlastnosti ideálnym riešením.

Vlastnosť deleter

Vlastností v Pythone je možné nielen čítať a nastavovať, ale aj mazať. Na tento účel nám Python ponúka možnosť definovať metódu, ktorá sa vyvolá, keď s našou vlastnosťou použijeme kľúčové slovo del. Túto metódu označujeme pomocou dekorátora @<property_name>.deleter.

Vytvorenie vlastnosti deleter

Predstavme si nasledujúcu situáciu. Máme triedu, ktorá reprezentuje dokument. Po zmazaní vlastnosti content chceme vymazať aj hodnotu atribútu _content, ktorý zastupovala, a nastaviť vlastnosť deleted na True:

class Document:
    def __init__(self, content):
        self._content = content
        self.deleted = False

    @property
    def content(self):
        if not self.deleted:
            return self._content
        return "The document has been deleted."

    @content.deleter
    def content(self):
        self._content = None
        self.deleted = True
        print("The document has been deleted.")

# Usage:
doc = Document("This is the content of my document.")
print(doc.content)  #  Displays: This is the content of my document.

del doc.content     # Displays: The document has been deleted.
print(doc.deleted)  # Displays: True

Zatiaľ čo setter je užitočný pre validáciu hodnôt alebo pre spustenie určitej logiky po nastavení hodnoty, deleter použijeme, ak chceme:

  • uvoľniť prostriedky – ak naša trieda spravuje prostriedky, ako sú súbory alebo sieťové spojenia, deleter využijeme na ich uvoľnenie,
  • aktualizovať súvisiace atribúty – rovnako ako v našom príklade s dokumentom môže byť potrebné aktualizovať niektoré súvisiace atribúty.

Deleter je v praxi oveľa menej bežný ako gettery a settery. Mnoho programátorov v Pythone ho nikdy nepoužije. Je to preto, že v mnohých prípadoch nie je potrebné explicitne ručiť za mazanie atribútov alebo ich prostriedkov. Ak však máme konkrétny dôvod na jeho použitie, je dobré vedieť, že túto možnosť máme k dispozícii.

V nasledujúcej lekcii, Vlastnosti v Pythone - Pokročilé vlastnosti a dedenie, sa v práci s vlastnosťami zameriame na dedenie, časté chyby a vytváranie vlastných dekorátorov pre vlastnosti.


 

Predchádzajúci článok
Dekorátory druhýkrát - Parametrické a triedne dekorátory
Všetky články v sekcii
Objektovo orientované programovanie v Pythone
Preskočiť článok
(neodporúčame)
Vlastnosti v Pythone - Pokročilé vlastnosti a dedenie
Článok pre vás napísal gcx11
Avatar
Užívateľské hodnotenie:
1 hlasov
(^_^)
Aktivity