Přetížení operátora Pythonu

Význam operátoru v Pythonu můžete změnit v závislosti na použitých operandech. V tomto kurzu se naučíte, jak používat přetížení operátorů v programování objektově orientovaného Pythonu.

Přetížení operátora Pythonu

Operátoři Pythonu pracují pro integrované třídy. Stejný operátor se ale chová odlišně u různých typů. Například +operátor provede aritmetické sčítání na dvou číslech, sloučí dva seznamy nebo zřetězí dva řetězce.

Tato funkce v Pythonu, která umožňuje stejnému operátorovi mít jiný význam podle kontextu, se nazývá přetížení operátoru.

Co se tedy stane, když je použijeme s objekty třídy definované uživatelem? Uvažujme o následující třídě, která se pokusí simulovat bod ve 2D souřadném systému.

 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ýstup

 Traceback (poslední hovor poslední): Soubor "", řádek 9, v tisku (p1 + p2) TypeError: nepodporované typy operandů pro +: 'Point' a 'Point'

Tady vidíme, že a TypeErrorbylo zvýšeno, protože Python nevěděl, jak přidat dva Pointobjekty dohromady.

Této úlohy však můžeme v Pythonu dosáhnout přetížením operátora. Nejprve si ale pojďme představit speciální funkce.

Speciální funkce Pythonu

Funkce třídy, které začínají dvojitým podtržítkem, __se v Pythonu nazývají speciální funkce.

Tyto funkce nejsou typické funkce, které definujeme pro třídu. __init__()Funkci jsme definovali výše, je jedním z nich. Volá se pokaždé, když vytvoříme nový objekt této třídy.

V Pythonu existuje řada dalších speciálních funkcí. Navštivte speciální funkce Pythonu, kde se o nich dozvíte více.

Pomocí speciálních funkcí můžeme naši třídu kompatibilní s integrovanými funkcemi.

 >>> p1 = Point(2,3) >>> print(p1) 

Předpokládejme, že chceme, aby print()funkce tiskla souřadnice Pointobjektu namísto toho, co jsme dostali. V __str__()naší třídě můžeme definovat metodu, která řídí, jak se objekt vytiskne. Pojďme se podívat, jak toho můžeme dosáhnout:

 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)

Nyní zkusme print()funkci znovu.

 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ýstup

 (2, 3)

To je lepší. Ukázalo se, že tato stejná metoda je vyvolána, když použijeme vestavěnou funkci str()nebo format().

 >>> str(p1) '(2,3)' >>> format(p1) '(2,3)'

Když tedy použijete str(p1)nebo format(p1), Python interně volá p1.__str__()metodu. Odtud název, speciální funkce.

Nyní se vraťme k přetížení operátora.

Přetížení operátora +

K přetížení +operátora budeme muset implementovat __add__()funkci ve třídě. S velkou mocí přichází i velká odpovědnost. V této funkci můžeme dělat, co se nám líbí. Je však rozumnější vrátit Pointobjekt souřadnicového souč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)

Nyní zkusme operaci přidání znovu:

 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ýstup

 (3,5)

Ve skutečnosti se stane, že když použijete p1 + p2, volá Python, p1.__add__(p2)což je naopak Point.__add__(p1,p2). Poté se provede operace přidání způsobem, který jsme zadali.

Podobně můžeme přetížit i další operátory. Speciální funkce, kterou musíme implementovat, je uvedena v tabulce níže.

Operátor Výraz Vnitřně
Přidání p1 + p2 p1.__add__(p2)
Odčítání p1 - p2 p1.__sub__(p2)
Násobení p1 * p2 p1.__mul__(p2)
Napájení p1 ** p2 p1.__pow__(p2)
Divize p1 / p2 p1.__truediv__(p2)
Podlahové dělení p1 // p2 p1.__floordiv__(p2)
Zbytek (modulo) p1 % p2 p1.__mod__(p2)
Bitový posun vlevo p1 << p2 p1.__lshift__(p2)
Bitový posun doprava p1>> p2 p1.__rshift__(p2)
Bitové AND p1 & p2 p1.__and__(p2)
Bitové NEBO p1 | p2 p1.__or__(p2)
Bitový XOR p1 p2 p1.__xor__(p2)
Bitové NENÍ ~p1 p1.__invert__()

Operátoři porovnání přetížení

Python neomezuje přetížení operátorů pouze na aritmetické operátory. Můžeme také přetížit operátory porovnání.

Předpokládejme, že jsme chtěli do <naší Pointtřídy implementovat symbol menší než symbol .

Porovnejme velikost těchto bodů od počátku a pro tento účel vraťme výsledek. Lze jej implementovat následujícím způsobem.

 # 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)

Zajímavé články...