CodeGym /Corso Java /Python SELF IT /Sovraccarico degli operatori

Sovraccarico degli operatori

Python SELF IT
Livello 20 , Lezione 0
Disponibile

6.1 Metodi magici

Il sovraccarico degli operatori in Python permette di definire o modificare il comportamento degli operatori incorporati (ad esempio, +, -, *, /) per le classi personalizzate. Questo si fa tramite metodi speciali, noti anche come metodi magici.

Ad esempio, nel tuo classe puoi sovraccaricare gli operatori di confronto:

Operatore Metodo senza trattino basso Firma del metodo
== eq() __eq__(self, other)
!= ne() __ne__(self, other)
< lt() __lt__(self, other)
<= le() __le__(self, other)
> gt() __gt__(self, other)
>= ge() __ge__(self, other)

Supponiamo che tu abbia scritto la tua classe e voglia che gli oggetti della tua classe vengano confrontati proprio come desideri. Devi solo implementare nella tua classe il metodo «__eq__», e Python lo chiamerà ogni volta che nel codice vengono confrontati oggetti della tua classe.

Esempio:


class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        
    def __eq__(self, other):
        return self.x == other.x and self.y == other.y
        
# Utilizzo
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1 == v2)  # Stampa: True
print(v1 == v3)  # Stampa: False

Ogni volta che confronti due dei tuoi oggetti, Python controlla se esiste una funzione «__eq__» implementata. Se c'è, la chiama. Se invece non c'è, confronterà semplicemente i puntatori agli oggetti.

In realtà, nell'esempio sopra è scritto (bisogna solo aggiungere il controllo sulla presenza del metodo):


# Utilizzo
v1 = Vector(2, 3)
v2 = Vector(2, 3)
v3 = Vector(4, 5)
print(v1.__eq__(v2))  # Stampa: True
print(v1.__eq__(v3))  # Stampa: False

6.2 Elenco di tutti gli operatori

In totale sono disponibili 6 gruppi di operatori per il sovraccarico.

Operatori aritmetici:

Operatore Metodo senza trattino basso Firma del metodo
+ add __add__(self, other)
- sub __sub__(self, other)
* mul __mul__(self, other)
/ truediv __truediv__(self, other)
// floordiv __floordiv__(self, other)
% mod __mod__(self, other)
** pow __pow__(self, other)

Operatori di confronto:

Operatore Metodo senza trattino basso Firma del metodo
== eq __eq__(self, other)
!= ne __ne__(self, other)
< lt __lt__(self, other)
<= le __le__(self, other)
> gt __gt__(self, other)
>= ge __ge__(self, other)

Operatori logici:

Operatore Metodo senza trattino basso Firma del metodo
& and __and__(self, other)
| or __or__(self, other)
^ xor __xor__(self, other)
~ invert __invert__(self)

Operatori di indicizzazione e slicing:

Operatore Metodo
obj[key] __getitem__(self, key)
obj[key] = value __setitem__(self, key, value)
del obj[key] __delitem__(self, key)

Operatori unari:

Operatore Metodo
- __neg__(self)
+ __pos__(self)
abs() __abs__(self)
~ __invert__(self)

Operatori di assegnazione:

Operatore Metodo
+= __iadd__(self, other)
-= __isub__(self, other)
*= __imul__(self, other)
/= __itruediv__(self, other)
//= __ifloordiv__(self, other)
%= __imod__(self, other)
**= __ipow__(self, other)

Forse è per questo che Python è così lento – ogni volta prima di eseguire un operatore cerca una funzione equivalente nella classe e in tutte le sue classi parenti. Tuttavia, questo permette di scrivere il codice più compatto al mondo :)

6.3 Operatore di indicizzazione

Che si possano confrontare oggetti o sottrarre insiemi è in un certo senso ovvio. E te ne accorgerai da solo se scriverai una classe che presuppone operazioni logiche o matematiche su di essa.

Voglio discutere con te un esempio interessante – come l'operatore di indicizzazione. Iniziamo subito con un esempio di codice:


class CustomList:
    def __init__(self, data):
        self.data = data
        
    def __getitem__(self, index):
        return self.data[index]
        
    def __setitem__(self, index, value):
        self.data[index] = value
        
    def __delitem__(self, index):
        del self.data[index]
        
    def __repr__(self):
        return repr(self.data)
        
# Utilizzo
c_list = CustomList([1, 2, 3, 4, 5])
print(c_list[1])  # Stampa: 2
c_list[1] = 10
print(c_list)  # Stampa: [1, 10, 3, 4, 5]
del c_list[1]
print(c_list)  # Stampa: [1, 3, 4, 5]

Qui vediamo un esempio di tre operazioni:

  • Lettura dei dati tramite indice
  • Scrittura dei dati tramite indice
  • E persino eliminazione dei dati tramite indice.

E in effetti non è affatto necessario che i dati all'interno siano memorizzati sotto forma di lista. O l'indice non deve necessariamente essere un numero. Ad esempio, la classe dictionary (dizionario) è implementata proprio così.

Creare una SuperList

Ricordi la classe list? Puoi assegnare elementi, ma solo con quegli indici che già esistono. Creiamo una nostra classe, chiamiamola SuperList, ai cui elementi potrai accedere da qualsiasi indice:

  • Se l'indice < 0, allora inseriamo l'elemento all'inizio
  • Se l'indice >= len, allora aggiungiamo l'elemento alla fine
  • Negli altri casi restituiamo semplicemente l'elemento

Esempio:


class SuperList(list):
    def __init__(self, value):
        super().__init__(value)
        
    def __setitem__(self, index, value):
        if index >= len(self):
            super().append(value)
        elif index < 0:
            super().insert(0, value)
        else:
            super().__setitem__(index, value)
        
lst = SuperList([1, 2, 3])
lst[200] = 100
lst[-200] = 99
print(lst)  # [99, 1, 2, 3, 100]

Quindi il sovraccarico degli indici è una grande possibilità, e ti consiglio di usarlo in pratica. E per oggi è tutto.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION