Sovraccarico degli operatori Python

È 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 è TypeErrorstato sollevato, poiché Python non sapeva come aggiungere due Pointoggetti 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 Pointdell'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 Pointoggetto 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 Pointclasse.

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)

Articoli interessanti...