È possibile modificare il significato di un operatore in Python a seconda degli operandi utilizzati. In questo tutorial imparerai come utilizzare l'overloading degli operatori nella programmazione orientata agli oggetti di Python.
Sovraccarico degli operatori Python
Gli operatori Python funzionano per le classi incorporate. Ma lo stesso operatore si comporta in modo diverso con tipi diversi. Ad esempio, l' +
operatore eseguirà l'addizione aritmetica su due numeri, unirà due elenchi o concatenerà due stringhe.
Questa funzionalità in Python che consente allo stesso operatore di avere un significato diverso a seconda del contesto è chiamata sovraccarico dell'operatore.
Quindi cosa succede quando li usiamo con oggetti di una classe definita dall'utente? Consideriamo la seguente classe, che cerca di simulare un punto nel sistema di coordinate 2-D.
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)
Produzione
Traceback (la chiamata più recente per ultima): File "", riga 9, in stampa (p1 + p2) TypeError: tipi di operandi non supportati per +: 'Point' e 'Point'
Qui, possiamo vedere che a è TypeError
stato sollevato, poiché Python non sapeva come aggiungere due Point
oggetti insieme.
Tuttavia, possiamo ottenere questo compito in Python tramite il sovraccarico di operatori. Ma prima, diamo un'idea delle funzioni speciali.
Funzioni speciali di Python
Le funzioni di classe che iniziano con un doppio trattino basso __
sono chiamate funzioni speciali in Python.
Queste funzioni non sono le funzioni tipiche che definiamo per una classe. La __init__()
funzione che abbiamo definito sopra è una di queste. Viene chiamato ogni volta che creiamo un nuovo oggetto di quella classe.
Ci sono numerose altre funzioni speciali in Python. Visita le funzioni speciali di Python per saperne di più.
Usando funzioni speciali, possiamo rendere la nostra classe compatibile con le funzioni integrate.
>>> p1 = Point(2,3) >>> print(p1)
Supponiamo di voler che la print()
funzione stampi le coordinate Point
dell'oggetto invece di ciò che abbiamo ottenuto. Possiamo definire un __str__()
metodo nella nostra classe che controlla come l'oggetto viene stampato. Diamo un'occhiata a come possiamo ottenere questo:
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)
Ora proviamo di print()
nuovo la funzione.
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)
Produzione
(2, 3)
Così va meglio. Si scopre che questo stesso metodo viene richiamato quando usiamo la funzione incorporata str()
o format()
.
>>> str(p1) '(2,3)' >>> format(p1) '(2,3)'
Quindi, quando usi str(p1)
o format(p1)
, Python chiama internamente il p1.__str__()
metodo. Da qui il nome, funzioni speciali.
Ora torniamo al sovraccarico degli operatori.
Sovraccarico dell'operatore +
Per sovraccaricare l' +
operatore, avremo bisogno di implementare la __add__()
funzione nella classe. Con un grande potere viene una grande responsabilità. Possiamo fare quello che vogliamo, all'interno di questa funzione. Ma è più sensato restituire un Point
oggetto della somma delle coordinate.
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)
Ora proviamo di nuovo l'operazione di addizione:
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)
Produzione
(3,5)
Quello che effettivamente accade è che, quando usi p1 + p2
, Python chiama p1.__add__(p2)
che a sua volta è Point.__add__(p1,p2)
. Successivamente, l'operazione di aggiunta viene eseguita nel modo da noi specificato.
Allo stesso modo, possiamo sovraccaricare anche altri operatori. La funzione speciale che dobbiamo implementare è tabulata di seguito.
Operatore | Espressione | Internamente |
---|---|---|
Aggiunta | p1 + p2 | p1.__add__(p2) |
Sottrazione | p1 - p2 | p1.__sub__(p2) |
Moltiplicazione | p1 * p2 | p1.__mul__(p2) |
Energia | p1 ** p2 | p1.__pow__(p2) |
Divisione | p1 / p2 | p1.__truediv__(p2) |
Divisione pavimento | p1 // p2 | p1.__floordiv__(p2) |
Resto (modulo) | p1 % p2 | p1.__mod__(p2) |
Spostamento sinistro bit per bit | p1 << p2 | p1.__lshift__(p2) |
Spostamento bit per bit destro | p1>> p2 | p1.__rshift__(p2) |
Bitwise AND | p1 & p2 | p1.__and__(p2) |
OR bit per bit | p1 | p2 | p1.__or__(p2) |
Bitwise XOR | p1 p2 | p1.__xor__(p2) |
Bitwise NON | ~p1 | p1.__invert__() |
Sovraccarico degli operatori di confronto
Python non limita il sovraccarico degli operatori ai soli operatori aritmetici. Possiamo anche sovraccaricare gli operatori di confronto.
Supponiamo di voler implementare il simbolo minore di <
simbolo nella nostra Point
classe.
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)