Význam operátora v Pythone môžete zmeniť v závislosti od použitých operandov. V tomto výučbe sa dozviete, ako používať preťaženie operátorov v programovaní zameranom na objekt Python.
Preťaženie operátora Python
Operátori Pythonu pracujú pre vstavané triedy. Rovnaký operátor sa ale pri rôznych typoch správa inak. Napríklad +
operátor vykoná aritmetické sčítanie na dvoch číslach, zlúči dva zoznamy alebo spojí dva reťazce.
Táto funkcia v Pythone, ktorá umožňuje tomu istému operátorovi mať odlišný význam podľa kontextu, sa nazýva preťaženie operátora.
Čo sa teda stane, keď ich použijeme s objektmi triedy definovanej používateľom? Uvažujme o nasledujúcej triede, ktorá sa pokúša simulovať bod v 2-D súradnicovom systéme.
class Point: def __init__(self, x=0, y=0): self.x = x self.y = y p1 = Point(1, 2) p2 = Point(2, 3) print(p1+p2)
Výkon
Traceback (posledný hovor naposledy): File "", riadok 9, v tlači (p1 + p2) TypeError: nepodporované typy operandov pre +: 'Point' a 'Point'
Tu vidíme, že TypeError
bolo zvýšené a, pretože Python nevedel pridať dva Point
objekty k sebe.
Túto úlohu však môžeme v Pythone dosiahnuť preťažením operátora. Najskôr si ale urobme predstavu o špeciálnych funkciách.
Špeciálne funkcie v Pythone
Funkcie triedy, ktoré začínajú dvojitým podčiarkovníkom, __
sa v Pythone nazývajú špeciálne funkcie.
Tieto funkcie nie sú typickými funkciami, ktoré definujeme pre triedu. __init__()
Funkciu sme definovali vyššie, je jedným z nich. Zavolá sa vždy, keď vytvoríme nový objekt tejto triedy.
V Pythone existuje množstvo ďalších špeciálnych funkcií. Navštívte Špeciálne funkcie Pythonu a dozviete sa o nich viac.
Pomocou špeciálnych funkcií môžeme dosiahnuť, aby bola naša trieda kompatibilná so zabudovanými funkciami.
>>> p1 = Point(2,3) >>> print(p1)
Predpokladajme, že chceme, aby print()
funkcia tlačila súradnice Point
objektu namiesto toho, čo sme dostali. V __str__()
našej triede môžeme definovať metódu, ktorá riadi, ako sa bude objekt tlačiť. Pozrime sa, ako to môžeme dosiahnuť:
class Point: def __init__(self, x = 0, y = 0): self.x = x self.y = y def __str__(self): return "((0),(1))".format(self.x,self.y)
Teraz skúsime print()
funkciu znova.
class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return "((0), (1))".format(self.x, self.y) p1 = Point(2, 3) print(p1)
Výkon
(2, 3)
To je lepšie. Ukázalo sa, že rovnaká metóda je vyvolaná, keď použijeme vstavanú funkciu str()
alebo format()
.
>>> str(p1) '(2,3)' >>> format(p1) '(2,3)'
Takže keď použijete str(p1)
alebo format(p1)
, Python interne zavolá p1.__str__()
metódu. Odtiaľ pochádza aj názov, špeciálne funkcie.
Teraz sa vráťme k preťaženiu operátora.
Preťaženie operátora +
Na preťaženie +
operátora budeme musieť __add__()
v triede implementovať funkciu. S veľkou mocou prichádza veľká zodpovednosť. V rámci tejto funkcie môžeme robiť, čo sa nám páči. Je však rozumnejšie vrátiť Point
objekt súradnicového súčtu.
class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return "((0),(1))".format(self.x, self.y) def __add__(self, other): x = self.x + other.x y = self.y + other.y return Point(x, y)
Teraz skúsime operáciu pridania znova:
class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return "((0),(1))".format(self.x, self.y) def __add__(self, other): x = self.x + other.x y = self.y + other.y return Point(x, y) p1 = Point(1, 2) p2 = Point(2, 3) print(p1+p2)
Výkon
(3,5)
Čo sa vlastne stane, je to, že keď použijete p1 + p2
, zavolá Python, p1.__add__(p2)
čo zase je Point.__add__(p1,p2)
. Potom sa vykoná operácia pridania spôsobom, ktorý sme špecifikovali.
Podobne môžeme preťažiť aj ostatných operátorov. Špeciálna funkcia, ktorú musíme implementovať, je uvedená v tabuľke nižšie.
Prevádzkovateľ | Vyjadrenie | Interne |
---|---|---|
Dodatok | p1 + p2 | p1.__add__(p2) |
Odčítanie | p1 - p2 | p1.__sub__(p2) |
Násobenie | p1 * p2 | p1.__mul__(p2) |
Moc | p1 ** p2 | p1.__pow__(p2) |
Divízia | p1 / p2 | p1.__truediv__(p2) |
Podlahové rozdelenie | p1 // p2 | p1.__floordiv__(p2) |
Zvyšok (modulo) | p1 % p2 | p1.__mod__(p2) |
Bitový posun vľavo | p1 << p2 | p1.__lshift__(p2) |
Bitový posun doprava | p1>> p2 | p1.__rshift__(p2) |
Bitové AND | p1 & p2 | p1.__and__(p2) |
Bitové ALEBO | p1 | p2 | p1.__or__(p2) |
Bitový XOR | p1 p2 | p1.__xor__(p2) |
Bitove NIE | ~p1 | p1.__invert__() |
Prevádzkovatelia porovnania preťaženia
Python neobmedzuje preťaženie operátora iba na aritmetické operátory. Môžeme preťažiť aj operátorov porovnania.
Predpokladajme, že sme chceli do <
našej Point
triedy implementovať symbol menej ako symbol .
Porovnajme veľkosť týchto bodov od počiatku a vráťme výsledok na tento účel. Môže sa implementovať nasledovne.
# overloading the less than operator class Point: def __init__(self, x=0, y=0): self.x = x self.y = y def __str__(self): return "((0),(1))".format(self.x, self.y) def __lt__(self, other): self_mag = (self.x ** 2) + (self.y ** 2) other_mag = (other.x ** 2) + (other.y ** 2) return self_mag < other_mag p1 = Point(1,1) p2 = Point(-2,-3) p3 = Point(1,-1) # use less than print(p1
Output
True False False
Similarly, the special functions that we need to implement, to overload other comparison operators are tabulated below.
Operator Expression Internally
Less than p1 < p2
p1.__lt__(p2)
Less than or equal to p1 <= p2
p1.__le__(p2)
Equal to p1 == p2
p1.__eq__(p2)
Not equal to p1 != p2
p1.__ne__(p2)
Greater than p1> p2
p1.__gt__(p2)
Greater than or equal to p1>= p2
p1.__ge__(p2)