Przeciążanie operatorów języka Python

Możesz zmienić znaczenie operatora w Pythonie w zależności od użytych operandów. Z tego samouczka dowiesz się, jak używać przeciążania operatorów w programowaniu obiektowym w języku Python.

Przeciążanie operatorów języka Python

Operatory Pythona działają dla klas wbudowanych. Ale ten sam operator zachowuje się inaczej w przypadku różnych typów. Na przykład +operator wykona arytmetyczne dodawanie dwóch liczb, połączy dwie listy lub połączy dwa ciągi.

Ta funkcja w Pythonie, która pozwala temu samemu operatorowi mieć różne znaczenie w zależności od kontekstu, nazywana jest przeciążeniem operatora.

Więc co się dzieje, gdy używamy ich z obiektami klasy zdefiniowanej przez użytkownika? Rozważmy następującą klasę, która próbuje zasymulować punkt w 2-D układzie współrzędnych.

 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)

Wynik

 Traceback (ostatnie wywołanie ostatnie): Plik „”, wiersz 9, w druku (p1 + p2) TypeError: nieobsługiwane typy operandów dla +: 'Point' i 'Point'

Tutaj widzimy, że TypeErrorpodniesiono a, ponieważ Python nie wiedział, jak dodać do siebie dwa Pointobiekty.

Jednak zadanie to możemy osiągnąć w Pythonie poprzez przeciążenie operatorów. Ale najpierw przyjmijmy pojęcie o funkcjach specjalnych.

Funkcje specjalne Pythona

Funkcje klas rozpoczynające się od podwójnego podkreślenia __nazywane są w Pythonie funkcjami specjalnymi.

Te funkcje nie są typowymi funkcjami, które definiujemy dla klasy. __init__()Funkcja określiliśmy powyżej jest jednym z nich. Jest wywoływana za każdym razem, gdy tworzymy nowy obiekt tej klasy.

W Pythonie jest wiele innych funkcji specjalnych. Odwiedź funkcje specjalne języka Python, aby dowiedzieć się więcej o nich.

Korzystając z funkcji specjalnych, możemy uczynić naszą klasę kompatybilną z funkcjami wbudowanymi.

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

Załóżmy, że chcemy, aby print()funkcja wypisała współrzędne Pointobiektu zamiast tego, co otrzymaliśmy. __str__()W naszej klasie możemy zdefiniować metodę, która kontroluje sposób drukowania obiektu. Spójrzmy, jak możemy to osiągnąć:

 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 spróbujmy print()ponownie tej funkcji.

 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)

Wynik

 (2, 3)

Tak lepiej. Okazuje się, że ta sama metoda jest wywoływana, gdy używamy funkcji wbudowanej str()lub format().

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

Tak więc, gdy używasz str(p1)or format(p1), Python wewnętrznie wywołuje p1.__str__()metodę. Stąd nazwa, funkcje specjalne.

Wróćmy teraz do przeciążenia operatora.

Przeciążanie operatora +

Aby przeciążyć +operatora, będziemy musieli zaimplementować __add__()funkcję w klasie. Z dużą mocą przychodzi duża odpowiedzialność. W ramach tej funkcji możemy robić, co nam się podoba. Ale rozsądniej jest zwrócić Pointobiekt sumy współrzędnych.

 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 spróbujmy ponownie dodać operację:

 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)

Wynik

 (3,5)

What actually happens is that, when you use p1 + p2, Python calls p1.__add__(p2) which in turn is Point.__add__(p1,p2). After this, the addition operation is carried out the way we specified.

Similarly, we can overload other operators as well. The special function that we need to implement is tabulated below.

Operator Expression Internally
Addition p1 + p2 p1.__add__(p2)
Subtraction p1 - p2 p1.__sub__(p2)
Multiplication p1 * p2 p1.__mul__(p2)
Power p1 ** p2 p1.__pow__(p2)
Division p1 / p2 p1.__truediv__(p2)
Floor Division p1 // p2 p1.__floordiv__(p2)
Remainder (modulo) p1 % p2 p1.__mod__(p2)
Bitwise Left Shift p1 << p2 p1.__lshift__(p2)
Bitwise Right Shift p1>> p2 p1.__rshift__(p2)
Bitwise AND p1 & p2 p1.__and__(p2)
Bitwise OR p1 | p2 p1.__or__(p2)
Bitwise XOR p1 p2 p1.__xor__(p2)
Bitwise NOT ~p1 p1.__invert__()

Overloading Comparison Operators

Python does not limit operator overloading to arithmetic operators only. We can overload comparison operators as well.

Suppose we wanted to implement the less than symbol < symbol in our Point class.

Let us compare the magnitude of these points from the origin and return the result for this purpose. It can be implemented as follows.

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

Interesujące artykuły...