IT rekvalifikácia. Seniorní programátori zarábajú až 6 000 €/mesiac a rekvalifikácia je prvým krokom. Zisti, ako na to!

20. diel - Magické metódy v Pythone

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

V nasledujúcom tutoriále objektovo orientovaného programovania v Pythone sa zameriame na magické (dunder) metódy objektov. Znalosť dunder metód nám poskytne hlbšie pochopenie toho, ako Python funguje "pod kapotou". Vďaka tomu budeme schopní lepšie rozumieť správaniu objektov a ich interakciám s jazykovými konštruktmi.

Magické metódy

Magické (dunder) metódy sú kľúčovou súčasťou Pythona a tvoria základ mnohých jeho OOP funkcií. Názov "dunder" pochádza z anglického "double underscore" (dvojité podčiarkovníky), čo odkazuje na ich typický zápis, napríklad __init__() alebo __str__(). Tieto metódy boli do Pythona pridané, aby umožnili vývojárom definovať správanie objektov v rôznych kontextoch, ako je inicializácia, reprezentácia, aritmetické operácie a mnoho ďalších.

S niekoľkými týmito metódami sme sa už stretli, ako napríklad s magickou metódou __init__() na inicializáciu objektu alebo s metódou __str__() na vypísanie jeho ľudsky čitateľnej reprezentácie.

Prehľad magických dunder metód

Dunder metódy si pre lepší prehľad rozdelíme do niekoľkých kategórií podľa ich funkcií:

1. Základné dunder metódy

  • objektová inicializácia a reprezentácia - __init__(), __str__(), __repr__(),
  • operátory porovnanie - __eq__(), __lt__(), __gt__(), a ďalšie,
  • logické operácie - __bool__()
  • matematické operátory - __add__(), __sub__(), __mul__(), __truediv__(), a ďalšie,
  • správa kontextu - __enter__(), __exit__() (pre použitie vo with príkaze).
2. Pokročilé dunder metódy
  • atribútové a indexové operácie - __getattr__(), __setattr__(), __delattr__(), __getitem__(), __setitem__(),
  • volanie objektov - __call__() (premena objektu na volateľný objekt),
  • správa inštancií - __new__() (používa sa na tvorbu nových inštancií).
3. Špeciálne prípady
  • vytvorenie užívateľsky definovaných kontajnerov - __len__(), __getitem__(),
  • custom iterátory a generátory - __iter__() a __next__(),
  • správa pamäte a Garbage Collection - __del__().
Toto je len základný prehľad. V tejto lekcii sa budeme venovať detailne prvej kategórii. Vopred upozorníme, že mnoho dunder metód je hlboko prepojených s kolekciami, ktoré zatiaľ nepoznáme. Zoznámime sa s nimi v kurze Kolekcia v Pythone. Napriek tomu sa v príkladoch kolekciám vyhneme, aby boli čo najviac pochopiteľné. Poďme na to.

Základné dunder metódy

Začneme prehľadom a príklady použitia základných metód.

Objektová inicializácia a reprezentácia

Tieto metódy, ktoré už dobre poznáme, sú základným stavebným kameňom pre akúkoľvek triedu v Pythone.

Metódy __init__(), __str__() a __repr__()

Metódu __init__() Python volá, kedykoľvek vytvárame novú inštanciu triedy. Používa sa na inicializáciu atribútov. Metódy __str__() a __repr__() určujú, ako bude objekt reprezentovaný ako reťazec. Zatiaľ čo __str__() vracia čitateľnú reprezentáciu pre koncových užívateľov, __repr__() má za cieľ poskytnúť jednoznačnú reprezentáciu objektu, ktorá je často technickej povahy a vhodná pre vývojárov. Tu si príklady uvádzať nebudeme, so všetkými spomínanými metódami sme sa už detailne zoznámili skôr.

Operátory porovnanie

Na porovnávacie metódy sa pozrime vo forme tabuľky:

Metóda Slovný popis Reprezentuje kód
__lt__(self, other) menšie ako (less than) x < y
__le__(self, other) menší alebo rovný (less or equal) x <= y
__eq__(self, other) rovná sa (equal) x == y
__ne__(self, other) nerovná sa (not equal) x != y
__gt__(self, other) väčšia ako (greater than) x > y
__ge__(self, other) väčší alebo rovný (greater or equal) x >= y
Všetky porovnávacie metódy vracajú True alebo False, popr. vyvolajú výnimku , ak sa porovnávanie s druhým objektom nepodporuje. Ich syntax je rovnaká:
class Cislo:
    def __init__(self, hodnota):
        self.hodnota = hodnota

    def __gt__(self, jine_cislo):
        if isinstance(jine_cislo, Cislo):
            return self.hodnota > jine_cislo.hodnota
        else:
            raise ValueError("Nelze porovnat 'Cislo' s objektem jiného typu.")

pi = Cislo(3.14)
e = Cislo(2.74)

print(pi > e)  # volá pi.__gt__(e), e je "other"

# Příklad výjimky při pokusu porovnat 'Cislo' s 'str'
jina_hodnota = "text"
try:
    print(pi > jina_hodnota)  # vyvolá výjimku
except ValueError as error:
    print(error)  # vypíše chybovou zprávu

Logické operácie

Metóda pre logické operácie určuje, ako sa má objekt správať v kontexte pravdivostných testov a logických operácií.

Metóda __bool__()

Pozrime sa, ako dokážeme prispôsobiť správanie metódy pri prevode objektu na typ bool:

class Auto:
    def __init__(self, palivo):
        self.palivo = palivo

    def __bool__(self):
        # Auto je "True" (funkční), pokud má více než 10 litrů paliva
        return self.palivo > 10

# Testování
sluzebni_auto = Auto(5)  # Málo paliva
moje_auto = Auto(20) # Dostatek paliva

print(bool(sluzebni_auto))  # Vypíše False
print(bool(moje_auto))      # Vypíše True

V príklade metóda __bool__() kontroluje, či je v nádrži viac ako 10 litrov paliva. Ak áno, vracia True, inak False. Tým je dosiahnuté to, že hodnota bool() na inštancii triedy Auto priamo závisí od množstva paliva v nádrži.

Tento prístup je užitočný v situáciách, keď chceme, aby hodnota bool() objektu reprezentovala jeho stav podľa nejakého špecifického kritéria, ktoré je dôležité pre logiku nášho programu.

Matematické operátory

Matematické operátory v Pythone sú skvelým príkladom toho, ako dunder metódy umožňujú objektom reagovať na štandardné matematické operácie. Pozrieme sa na ne opäť vo forme tabuľky:

Metóda Slovný popis Reprezentuje kód
__add__(self, other) sčítanie +
__sub__(self, other) odčítanie -
__mul__(self, other) násobenie *
__truediv__(self, other) delenie /
__eq__(self, other) rovná sa =
__mod__(self, other) modulo %
__pow__(self, other[, modulo]) umocňovanie **
Tieto metódy umožňujú objektom pracovať s aritmetickými operátormi rovnako, ako by to boli bežné číselné typy. Ako príklad si definujeme triedu KomplexniCislo, ktorá bude reprezentovať komplexné čísla a bude implementovať súčet:
class KomplexniCislo:
    def __init__(self, realna, imaginarni):
        self.realna = realna
        self.imaginarni = imaginarni

    def __add__(self, other):
        return KomplexniCislo(self.realna + other.realna, self.imaginarni + other.imaginarni)

    def __str__(self):
        return f"{self.realna} + {self.imaginarni}i"

# Testování
prvni_komplex = KomplexniCislo(1, 2)
druhy_komplex = KomplexniCislo(3, 4)

vysledek = prvni_komplex + druhy_komplex
print(vysledek)  # Vypíše "4 + 6i"

Všetky spomenuté metódy umožňujú preťažiť správanie štandardných operátorov a prispôsobiť ich funkčnosť pre užívateľsky definované objekty.

Preťaženie operátorov

Python nám umožňuje modifikovať spôsob, akým štandardné operátory (ako +, -, *, /, <, == a ďalšie) fungujú s našimi vlastnými objektmi. Už sme si ukázali, že pre každý operátor existuje zodpovedajúca metóda. Teraz si ukážeme, ako ju definovať v rámci triedy, aby sa zmenila štandardná funkcionalita daného operátora.

Vytvoríme si triedu Vektor, ktorá reprezentuje 2D vektor a preťažuje niektorých matematických operátorov:

class Vektor:
    def __init__(self, souradnice_x, souradnice_y):
        self.souradnice_x = souradnice_x
        self.souradnice_y = souradnice_y

    def __repr__(self):
        return f"Vektor({self.souradnice_x}, {self.souradnice_y})"

    def __add__(self, dalsi_vektor):
        # Přetížení operátoru +
        return Vektor(self.souradnice_x + dalsi_vektor.souradnice_x, self.souradnice_y + dalsi_vektor.souradnice_y)

    def __sub__(self, dalsi_vektor):
        # Přetížení operátoru -
        return Vektor(self.souradnice_x - dalsi_vektor.souradnice_x, self.souradnice_y - dalsi_vektor.souradnice_y)

    def __mul__(self, skalarni_hodnota):
        # Přetížení operátoru * pro násobení skalárem
        return Vektor(self.souradnice_x * skalarni_hodnota, self.souradnice_y * skalarni_hodnota)

# Příklad použití
vektor1 = Vektor(2, 3)
vektor2 = Vektor(1, 1)
print(vektor1 + vektor2)  # Výstup: Vektor(3, 4)
print(vektor1 - vektor2)  # Výstup: Vektor(1, 2)
print(vektor1 * 3)        # Výstup: Vektor(6, 9)

Správa kontextu

V Pythone sa správa kontextu využíva hlavne na správne spracovanie zdrojov a na zabezpečenie, že sú tieto zdroje korektne uvoľnené alebo uzavreté po použití. Kľúčovým prvkom pre správu kontextu je využitie príkazu with, ktorý automaticky zaistí správne otvorenie a uzavretie zdrojov, ako sú súbory, sieťové pripojenia a podobne. Táto kapitola je zatiaľ trochu mimo našich obzorov, súborov a sietí sa budeme zaoberať v pokročilejších kurzoch. Napriek tomu vo výčte nesmie chýbať a príklad, ktorý si uvedieme, bude úplne v medziach našich znalostí.

Metóda __enter__()

Metóda __enter__() sa zavolá v okamihu, keď kód vstupuje do kontextového manažéra – teda do bloku kódu definovaného príkazom with. Typicky sa v tejto metóde vykonávajú inicializačné operácie, ako je otvorenie súboru alebo získanie zámku.

Metóda __exit__()

Metóda __exit__() sa zavolá na konci bloku kódu v príkaze with, bez ohľadu na to, či bol blok opustený normálne, alebo došlo k vyhodeniu výnimky. Táto metóda zvyčajne zahŕňa upratovacie operácie, ako je zatváranie súborov alebo uvoľnenie zdrojov. Má tri argumenty, ktoré reprezentujú typ výnimky, hodnotu výnimky a traceback, ak došlo k vyhodeniu výnimky.

Pozrime sa na príklad:

import time

class Casovac:
    def __enter__(self):
        self.start = time.time()
        return self

    def __exit__(self, exc_type, exc_val, traceback):
        self.end = time.time()
        print(f"Doba trvání: {self.end - self.start} sekund.")

# Použití:
with Casovac() as t:
    # Kód, který chceme změřit:
    for i in range(1000000):
        i *= 2
# Po ukončení bloku 'with' se vypíše doba trvání

Rozhodne nejde o kompletný zoznam všetkých dunder metód v daných kategóriách. To by jednak lekcia extrémne nadobudla na objeme a tiež by sa podobala skôr encyklopédii. Pre hlbšie štúdium je tu dokumentácia Pythona, kde je zoznam naozaj komplexný. To je pre túto lekciu všetko:-)

V budúcej lekcii, Magické metódy v Pythone druhýkrát , sa pozrieme na ďalšie, pokročilejšie magické metódy objektov.


 

Predchádzajúci článok
Vlastnosti v Pythone druhýkrát - Pokročilé vlastnosti a dedenie
Všetky články v sekcii
Objektovo orientované programovanie v Pythone
Preskočiť článok
(neodporúčame)
Magické metódy v Pythone druhýkrát
Článok pre vás napísal gcx11
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
(^_^)
Aktivity