Značenje operatora u Pythonu možete promijeniti ovisno o korištenim operandima. U ovom vodiču naučit ćete kako koristiti preopterećenje operatora u Python objektno orijentiranom programiranju.
Preopterećenje operatora Pythona
Python operateri rade za ugrađene klase. Ali isti se operator različito ponaša s različitim vrstama. Na primjer, +
operator će izvršiti aritmetičko sabiranje dva broja, spojiti dva popisa ili spojiti dva niza.
Ova značajka u Pythonu koja omogućava istom operatoru da ima različita značenja u skladu s kontekstom naziva se preopterećenje operatora.
Pa što se događa kada ih koristimo s objektima korisnički definirane klase? Razmotrimo sljedeću klasu koja pokušava simulirati točku u 2-D koordinatnom sustavu.
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)
Izlaz
Traceback (najnoviji zadnji poziv): Datoteka "", red 9, u ispisu (p1 + p2) TypeError: nepodržani tip (ovi) operanda za +: 'Point' i 'Point'
Ovdje možemo vidjeti da TypeError
je postavljeno a, jer Python nije znao dodati dva Point
objekta zajedno.
Međutim, ovaj zadatak u Pythonu možemo postići preopterećenjem operatora. Ali prvo, steknimo pojam o posebnim funkcijama.
Python posebne funkcije
Funkcije klase koje počinju dvostrukim donjim crtama __
nazivaju se posebnim funkcijama u Pythonu.
Te funkcije nisu tipične funkcije koje definiramo za klasu. __init__()
Funkcija mi je gore definirano je jedan od njih. Pozva se svaki put kada stvorimo novi objekt te klase.
U Pythonu postoje brojne druge posebne funkcije. Posjetite Python Special Functions da biste saznali više o njima.
Korištenjem posebnih funkcija našu klasu možemo učiniti kompatibilnom s ugrađenim funkcijama.
>>> p1 = Point(2,3) >>> print(p1)
Pretpostavimo da želimo da print()
funkcija ispisuje koordinate Point
objekta umjesto onoga što smo dobili. U __str__()
našoj klasi možemo definirati metodu koja kontrolira način ispisa predmeta. Pogledajmo kako to možemo postići:
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)
Pokušajmo print()
ponovo s funkcijom.
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)
Izlaz
(2, 3)
Tako je bolje. Ispada, da se ta ista metoda poziva kada koristimo ugrađenu funkciju str()
ili format()
.
>>> str(p1) '(2,3)' >>> format(p1) '(2,3)'
Dakle, kada koristite str(p1)
ili format(p1)
, Python interno poziva p1.__str__()
metodu. Otuda i naziv, posebne funkcije.
Vratimo se sada preopterećenju operatera.
Preopterećenje operatora +
Da bismo preopteretili +
operator, morat ćemo implementirati __add__()
funkciju u klasu. S velikom moći dolazi velika odgovornost. Unutar ove funkcije možemo raditi što god želimo. Ali razumnije je vratiti Point
objekt koordinatnog zbroja.
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)
Pokušajmo ponovo s operacijom zbrajanja:
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)
Izlaz
(3,5)
Ono što se zapravo događa je da, kada koristite p1 + p2
, Python poziva p1.__add__(p2)
što pak jest Point.__add__(p1,p2)
. Nakon toga, operacija zbrajanja izvodi se na način koji smo odredili.
Slično tome, možemo preopteretiti i druge operatore. Posebna funkcija koju trebamo implementirati prikazana je u nastavku.
Operater | Izraz | Interno |
---|---|---|
Dodatak | p1 + p2 | p1.__add__(p2) |
Oduzimanje | p1 - p2 | p1.__sub__(p2) |
Množenje | p1 * p2 | p1.__mul__(p2) |
Vlast | p1 ** p2 | p1.__pow__(p2) |
Podjela | p1 / p2 | p1.__truediv__(p2) |
Podna podjela | p1 // p2 | p1.__floordiv__(p2) |
Ostatak (po modulu) | p1 % p2 | p1.__mod__(p2) |
Pomicanje ulijevo ulijevo | p1 << p2 | p1.__lshift__(p2) |
Pomicanje udesno udesno | p1>> p2 | p1.__rshift__(p2) |
Bitno I | p1 & p2 | p1.__and__(p2) |
Bitno ILI | p1 | p2 | p1.__or__(p2) |
Bitno XOR | p1 p2 | p1.__xor__(p2) |
Bitno NE | ~p1 | p1.__invert__() |
Preopterećenje operatora usporedbe
Python ne ograničava preopterećenje operatora samo na aritmetičke operatore. Možemo preopteretiti i operatore usporedbe.
Pretpostavimo da smo željeli implementirati simbol manji od <
simbola u našu Point
klasu.
Usporedimo veličinu tih točaka iz ishodišta i vratimo rezultat u tu svrhu. Može se provesti na sljedeći način.
# 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)