Uno dei fattori che rende Python un linguaggio di programmazione così potente è la presenza dei magic method. In alcuni ambienti Pythonista potresti sentirli chiamare "dunder methods" per via della loro struttura con doppio underscore.
Il loro ruolo in Python è eseguire una procedura nota come "sovraccarico degli operatori" (operator overloading), che significa semplicemente attribuire un significato esteso a un operatore predefinito. In altre parole, il sovraccarico degli operatori serve ad aggiungere comportamenti personalizzati alle nostre classi per abilitarne l'uso con gli operatori di Python e le sue funzionalità built-in.
In questo articolo approfondiremo i magic method di Python:
Distinguendo la differenza tra metodi e funzioni
Spiegando cosa sono i magic method
Fornendo alcuni esempi in Python.
Dai un'occhiata a questo DataLab workbook per seguire il codice usato in questo tutorial.
Metodi Python vs Funzioni
Prima di entrare nel merito dei magic method, è importante capire le differenze tra un metodo e una funzione in Python.
Python usa i metodi per rappresentare il comportamento di un oggetto. I metodi sono quindi associati a un oggetto ed eseguono alcune operazioni sui dati presenti in un oggetto. Un altro fattore distintivo di un metodo è il parametro self, che deve sempre comparire come primo parametro passato al metodo.
Nota: non deve per forza chiamarsi self come primo parametro, ma i Pythonisti concordano universalmente che sia una best practice.
# Example of a methodclassHuman:# This is a methoddefwalk(self):print("I am walking")Offerto da
I metodi dipendono dalla classe con cui sono associati. Pertanto, per chiamare un metodo, è necessario creare un'istanza della classe prima di accedere al metodo con l'operatore punto.
# This will work
joe = Human()
joe.walk()"""
I am walking
"""# This will throw a NameError
walk()---------------------------------------------------------------------------
NameError Traceback (most recent call last)/tmp/ipykernel_153/2327344440.py in<module>45# This will throw a NameError---->6 walk()
NameError: name 'walk'isnot definedOfferto da
Una funzione, invece, è diversa: non dobbiamo creare un'istanza di una classe.
Le funzioni Python sono passi eseguiti come un blocco di codice solo quando vengono chiamate. Sono definite in modo indipendente da qualsiasi oggetto classe, quindi possono essere chiamate direttamente per nome. Non essendo associate ad alcuna classe, non dobbiamo passare self come parametro – i parametri sono opzionali.
In sostanza, una funzione è semplicemente un insieme di istruzioni ben definite che l'interprete utilizza per svolgere un compito.
# Example of a functiondefrun():print("I am running.")
run()"""
I am running.
"""Offerto da
Come approfondito nel nostro articolo How to call and write functions, le funzioni si presentano in due varianti: built-in e definite dall'utente.
Funzioni built-in: funzioni incluse nella libreria standard di Python.
Funzioni definite dall'utente: funzioni definite dall'utente – Python permette di definire e usare funzioni personalizzate accessibili in un programma Python.
Sotto molti aspetti, metodi e funzioni sono identici, ad esempio sono entrambi definiti con un'istruzione def. La differenza sostanziale è che i metodi sono associati a un oggetto e servono a operare sui dati contenuti all'interno di una classe, mentre le funzioni sono definite in modo indipendente e possono essere chiamate per nome ovunque in un programma.
Cosa sono i magic method di Python?
All'inizio del tutorial abbiamo menzionato che i magic method sono anche chiamati dunder methods a causa del loro doppio underscore. Con questo intendiamo che tutti i magic method di Python iniziano e finiscono con due underscore.
Il magic method più noto è __init__, che consente di inizializzare una classe con attributi specifici.
classEmployee:def__init__(self, name, age, role):
self.name = name
self.age = age
self.role = roleOfferto da
Per istanziare un oggetto di questa classe, dobbiamo specificare gli attributi name, age e role dell'istanza. Per esempio:
user_1 = Employee(name="John", age=24, role="Data Scientist")Offerto da
In caso contrario verrebbe sollevata una TypeError.
Il metodo __init__ rientra nella categoria dei magic method di inizializzazione e costruzione, ma è solo uno dei tanti. La tabella seguente illustra altri magic method di inizializzazione e costruzione.
__new__(cls, other)
Usato per creare una nuova istanza di una classe
__init__(self, other)
Chiamato dopo la creazione di una nuova istanza; tutti gli attributi passati all'espressione del costruttore della classe verranno usati come attributi.
__del__(self)
Conosciuto anche come distruttore; chiamato quando un'istanza sta per essere distrutta.
Il modo più semplice per concettualizzare i magic method è considerarli come un contratto tra la tua implementazione e l'interprete Python. Una delle clausole del contratto richiede a Python di eseguire alcune azioni dietro le quinte in determinate circostanze, come inizializzare un'istanza di classe con oggetti specifici.
In altre parole, non è tua responsabilità invocare direttamente un magic method chiamandolo: Python lo fa per te dietro le quinte.
Metodi di rappresentazione testuale
Python è un linguaggio di programmazione orientata agli oggetti (OOP) – in Python tutto è un oggetto. Quando crei un nuovo oggetto, crei implicitamente un oggetto correlato perché tutte le classi ereditano da object.
Nota: puoi anche rendere l'ereditarietà esplicita passando la classe object alla tua classe.
# This worksclassCar:pass
# This also worksclassVehicle(object):pass
car = Car()
vehicle = Vehicle()
print(car, vehicle, sep="\n")"""
<__main__.Car object at 0x7f80449dc0a0>
<__main__.Vehicle object at 0x7f80449dc1f0>
"""Offerto da
Nel codice sopra abbiamo creato due classi vuote, ma l'interprete Python sapeva comunque cosa stampare quando abbiamo chiamato la print. Questo è possibile perché tutte le classi ereditano dalla classe object (la madre di tutte le classi in Python), che ha un magic method chiamato __repr__, che la print richiama per restituire un valore al nostro programma principale.
Chi conosce l'ereditarietà sa che una classe figlia può ridefinire la sua classe genitore definendo un proprio metodo con lo stesso nome.
# Overriding the object __repr__classVehicle:def__repr__(self):returnf"{self.__class__.__qualname__}"
vehicle = Vehicle()print(vehicle)"""
Vehicle
"""Offerto da
Puoi anche usare il magic method __str__ per creare una rappresentazione testuale richiamata dalla print.
In effetti, il magic method __repr__ funge da comportamento di riserva per il magic method __str__. Quindi, quando chiamiamo la print, Python cerca prima il metodo __str__ definito nella tua classe e, in mancanza di questo, ricorre al metodo __repr__.
# Using __str__ for string representationclassVehicle:def__str__(self):returnf"{self.__class__.__qualname__}"
vehicle = Vehicle()print(vehicle)"""
Vehicle
"""Offerto da
La tabella seguente elenca altri magic method relativi alla rappresentazione testuale.
__str__(self)
Chiamato dalla funzione built-in str() di Python e dall'istruzione print per mostrare la rappresentazione testuale informale di un oggetto. Nota che non è richiesto che sia un'espressione Python valida.
__repr__(self)
Chiamato dalla funzione built-in repr() di Python e dalle conversioni di stringa per mostrare la rappresentazione testuale ufficiale di un oggetto. Nota che dovrebbe sembrare un'espressione Python valida, ma se non è possibile, è preferibile una stringa con una descrizione utile.
__unicode__(self)
Chiamato per implementare la funzione built-in unicode() di Python e restituisce un oggetto Unicode.
__hash__(self)
Chiamato dalla funzione built-in hash() di Python e dalle operazioni sui membri di collezioni hashate. Il metodo deve restituire un intero.
__nonzero__(self)
Chiamato dall'operazione built-in bool() di Python per implementare il test di veridicità. Il metodo deve restituire True o False (o il loro equivalente intero 1 o 0).
Metodi "magici" di incapsulamento
L'incapsulamento è uno dei concetti fondamentali della programmazione orientata agli oggetti (OOP). Si riferisce al raggruppamento dei dati con i metodi che operano su tali dati o alla restrizione dell'accesso diretto a determinati componenti all'interno di un oggetto.
Sviluppatori provenienti da altri linguaggi OOP contestano spesso il fatto che Python non abbracci pienamente l'incapsulamento per le classi. Sono abituati ad avere modificatori espliciti per metodi o campi che permettono di definire, ad esempio, attributi privati con getter e setter pubblici. La differenza in Python è che gran parte dell'incapsulamento avviene tramite i magic method.
Per esempio, __setattr__ è una soluzione di incapsulamento che ci consente di definire un comportamento per l'assegnazione a un attributo a prescindere dalla sua esistenza. In altre parole, si possono definire regole per i cambiamenti dei valori degli attributi.
import string
classAlphabet():def__setattr__(self, name, value):
self.__dict__[name]= value.upper()
a = Alphabet()# Assinging an attribute that does not exist# The setattr should convert it to caps despite being set as lowercase
a.alphabet = string.ascii_lowercase
print(a.alphabet)Offerto da
Nel codice sopra, abbiamo creato una classe chiamata Alphabet senza attributi, ma abbiamo detto a Python che volevamo mettere in maiuscolo qualsiasi attributo dell'istanza di classe che impostiamo.
Sappiamo che l'OOP può essere un po' ostica per alcuni lettori. Per metterti in pari con l'OOP in Python, dai un'occhiata al Python Programmer Track di DataCamp.
Magic method matematici
Un'altra categoria di magic method di Python sono i magic method matematici (noti anche come normali operatori aritmetici). Le espressioni sono create usando simboli speciali che chiamiamo "operatori" in Python. Usare tali operatori in un'espressione implica creare oggetti con magic method matematici. Il mancato rispetto di questa regola solleverà una TypeError.
classNumbers:def__init__(self, a, b):
self.a = a
self.b = b
set_a = Numbers(2,4)
set_b = Numbers(3,5)
print(set_a + set_b)"""
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/tmp/ipykernel_152/3639634723.py in <module>
7 set_b = Numbers(3, 5)
8
----> 9 print(set_a + set_b)
TypeError: unsupported operand type(s) for +: 'Numbers' and 'Numbers'
"""Offerto da
Nel codice sopra, abbiamo provato a creare più istanze della classe Numbers e ad aggiungerle tra loro, cosa che ha generato un errore come previsto. Una soluzione potrebbe essere creare un metodo nella nostra classe per sommare i numeri, ma ciò ci impedirebbe di creare espressioni.
Una soluzione migliore è implementare un magic method __add__ come segue:
# Using add operatorclassNumbers:def__init__(self, a, b):
self.a = a
self.b = b
def__add__(self, other):# Only permit Numbers objects to be addedifnotisinstance(other, Numbers):return NotImplemented
return Numbers(other.a + self.a, other.b + self.b)def__repr__(self):returnf"{self.__class__.__qualname__}({self.a}, {self.b})"
a = Numbers(2,4)
b = Numbers(3,5)print(a + b)# Should result in Numbers(5, 9)"""
RandomNumbers(5, 9)
"""Offerto da
L'esempio di codice sopra ci consente solo di sommare due oggetti Numbers. Implementiamo un altro magic method matematico che ci permetta di moltiplicare un oggetto Numbers per un intero.
# Multiplying Numbers with an integerclassNumbers:def__init__(self, a, b):
self.a = a
self.b = b
def__add__(self, other):# Only permit Numbers objects to be addedifnotisinstance(other, Numbers):return NotImplemented
return Numbers(other.a + self.a, other.b + self.b)def__mul__(self, other):ifnotisinstance(other,int):return NotImplemented
return Numbers(self.a * other, self.b * other)def__repr__(self):returnf"{self.__class__.__qualname__}({self.a}, {self.b})"
a = Numbers(2,4)print(a *5)# Should return 10, 20"""
RandomNumbers(10, 20)
"""Offerto da
Nel codice sopra, abbiamo aggiunto un magic method __mul__ per permetterci di moltiplicare i numeri della nostra classe personalizzata per un intero.
Nota che l'oggetto Numbers compare a sinistra dell'operatore * – non è un caso. Mettiamolo a destra dell'operando e osserviamo cosa succede.
- snip --
a = Numbers(2,4)print(3* a)---------------------------------------------------------------------------
TypeError Traceback (most recent call last)/tmp/ipykernel_152/2857655049.py in<module>1 a = Numbers(2,4)---->2print(3* a)
TypeError: unsupported operand type(s)for*:'int'and'Numbers'Offerto da
Python solleva una TypeError.
Il magic method __mul__ che abbiamo implementato copre solo il caso in cui l'oggetto Numbers si trovi sul lato sinistro dell'operatore *. Per estendere questa funzionalità, dobbiamo aggiungere il metodo inverso, __rmul__.
# Enabling reverse multiplicationclassNumbers:def__init__(self, a, b):
self.a = a
self.b = b
def__add__(self, other):# Only permit Numbers objects to be addedifnotisinstance(other, Numbers):return NotImplemented
return Numbers(other.a + self.a, other.b + self.b)def__mul__(self, other):ifnotisinstance(other,int):return NotImplemented
return Numbers(self.a * other, self.b * other)def__rmul__(self, other):return self.__mul__(other)def__repr__(self):returnf"{self.__class__.__qualname__}({self.a}, {self.b})"
a = Numbers(2,4)print(5* a)# Should return 10, 20"""
Numbers(10, 20)
"""Offerto da
Ora possiamo creare un'espressione di moltiplicazione senza dover considerare da che lato dell'operando compare l'oggetto Numbers.
Conclusione
Il principio di base per sfruttare i magic method di Python resta lo stesso: creare una classe e sovrascrivere i magic method della classe object. I magic method in Python sono davvero tanti, quindi questo tutorial sarebbe lunghissimo se decidessimo di coprirli tutti singolarmente. Ti consigliamo vivamente di consultare la documentazione di Python per farti un'idea della portata completa dei magic method che puoi usare per migliorare le tue competenze di programmazione in Python.
Scopri i 15 migliori server MCP remoti che stanno trasformando lo sviluppo AI nel 2026. Scopri come migliorano automazione, ragionamento, sicurezza e velocità dei workflow.
Uno dei fattori che rende Python un linguaggio di programmazione così potente è la presenza dei magic method. In alcuni ambienti Pythonista potresti sentirli chiamare "dunder methods" per via della loro struttura con doppio underscore.
Il loro ruolo in Python è eseguire una procedura nota come "sovraccarico degli operatori" (operator overloading), che significa semplicemente attribuire un significato esteso a un operatore predefinito. In altre parole, il sovraccarico degli operatori serve ad aggiungere comportamenti personalizzati alle nostre classi per abilitarne l'uso con gli operatori di Python e le sue funzionalità built-in.
In questo articolo approfondiremo i magic method di Python:
Dai un'occhiata a questo DataLab workbook per seguire il codice usato in questo tutorial.
Metodi Python vs Funzioni
Prima di entrare nel merito dei magic method, è importante capire le differenze tra un metodo e una funzione in Python.
Python usa i metodi per rappresentare il comportamento di un oggetto. I metodi sono quindi associati a un oggetto ed eseguono alcune operazioni sui dati presenti in un oggetto. Un altro fattore distintivo di un metodo è il parametro self, che deve sempre comparire come primo parametro passato al metodo.
Nota: non deve per forza chiamarsi self come primo parametro, ma i Pythonisti concordano universalmente che sia una best practice.
I metodi dipendono dalla classe con cui sono associati. Pertanto, per chiamare un metodo, è necessario creare un'istanza della classe prima di accedere al metodo con l'operatore punto.
Una funzione, invece, è diversa: non dobbiamo creare un'istanza di una classe.
Le funzioni Python sono passi eseguiti come un blocco di codice solo quando vengono chiamate. Sono definite in modo indipendente da qualsiasi oggetto classe, quindi possono essere chiamate direttamente per nome. Non essendo associate ad alcuna classe, non dobbiamo passare self come parametro – i parametri sono opzionali.
In sostanza, una funzione è semplicemente un insieme di istruzioni ben definite che l'interprete utilizza per svolgere un compito.
Come approfondito nel nostro articolo How to call and write functions, le funzioni si presentano in due varianti: built-in e definite dall'utente.
Sotto molti aspetti, metodi e funzioni sono identici, ad esempio sono entrambi definiti con un'istruzione def. La differenza sostanziale è che i metodi sono associati a un oggetto e servono a operare sui dati contenuti all'interno di una classe, mentre le funzioni sono definite in modo indipendente e possono essere chiamate per nome ovunque in un programma.
Cosa sono i magic method di Python?
All'inizio del tutorial abbiamo menzionato che i magic method sono anche chiamati dunder methods a causa del loro doppio underscore. Con questo intendiamo che tutti i magic method di Python iniziano e finiscono con due underscore.
Il magic method più noto è __init__, che consente di inizializzare una classe con attributi specifici.
Per istanziare un oggetto di questa classe, dobbiamo specificare gli attributi name, age e role dell'istanza. Per esempio:
In caso contrario verrebbe sollevata una TypeError.
Il metodo __init__ rientra nella categoria dei magic method di inizializzazione e costruzione, ma è solo uno dei tanti. La tabella seguente illustra altri magic method di inizializzazione e costruzione.
__new__(cls, other)
Usato per creare una nuova istanza di una classe
__init__(self, other)
Chiamato dopo la creazione di una nuova istanza; tutti gli attributi passati all'espressione del costruttore della classe verranno usati come attributi.
__del__(self)
Conosciuto anche come distruttore; chiamato quando un'istanza sta per essere distrutta.
Il modo più semplice per concettualizzare i magic method è considerarli come un contratto tra la tua implementazione e l'interprete Python. Una delle clausole del contratto richiede a Python di eseguire alcune azioni dietro le quinte in determinate circostanze, come inizializzare un'istanza di classe con oggetti specifici.
In altre parole, non è tua responsabilità invocare direttamente un magic method chiamandolo: Python lo fa per te dietro le quinte.
Metodi di rappresentazione testuale
Python è un linguaggio di programmazione orientata agli oggetti (OOP) – in Python tutto è un oggetto. Quando crei un nuovo oggetto, crei implicitamente un oggetto correlato perché tutte le classi ereditano da object.
Nota: puoi anche rendere l'ereditarietà esplicita passando la classe object alla tua classe.
Nel codice sopra abbiamo creato due classi vuote, ma l'interprete Python sapeva comunque cosa stampare quando abbiamo chiamato la print. Questo è possibile perché tutte le classi ereditano dalla classe object (la madre di tutte le classi in Python), che ha un magic method chiamato __repr__, che la print richiama per restituire un valore al nostro programma principale.
Chi conosce l'ereditarietà sa che una classe figlia può ridefinire la sua classe genitore definendo un proprio metodo con lo stesso nome.
Puoi anche usare il magic method __str__ per creare una rappresentazione testuale richiamata dalla print.
In effetti, il magic method __repr__ funge da comportamento di riserva per il magic method __str__. Quindi, quando chiamiamo la print, Python cerca prima il metodo __str__ definito nella tua classe e, in mancanza di questo, ricorre al metodo __repr__.
La tabella seguente elenca altri magic method relativi alla rappresentazione testuale.
__str__(self)
Chiamato dalla funzione built-in str() di Python e dall'istruzione print per mostrare la rappresentazione testuale informale di un oggetto. Nota che non è richiesto che sia un'espressione Python valida.
__repr__(self)
Chiamato dalla funzione built-in repr() di Python e dalle conversioni di stringa per mostrare la rappresentazione testuale ufficiale di un oggetto. Nota che dovrebbe sembrare un'espressione Python valida, ma se non è possibile, è preferibile una stringa con una descrizione utile.
__unicode__(self)
Chiamato per implementare la funzione built-in unicode() di Python e restituisce un oggetto Unicode.
__hash__(self)
Chiamato dalla funzione built-in hash() di Python e dalle operazioni sui membri di collezioni hashate. Il metodo deve restituire un intero.
__nonzero__(self)
Chiamato dall'operazione built-in bool() di Python per implementare il test di veridicità. Il metodo deve restituire True o False (o il loro equivalente intero 1 o 0).
Metodi "magici" di incapsulamento
L'incapsulamento è uno dei concetti fondamentali della programmazione orientata agli oggetti (OOP). Si riferisce al raggruppamento dei dati con i metodi che operano su tali dati o alla restrizione dell'accesso diretto a determinati componenti all'interno di un oggetto.
Sviluppatori provenienti da altri linguaggi OOP contestano spesso il fatto che Python non abbracci pienamente l'incapsulamento per le classi. Sono abituati ad avere modificatori espliciti per metodi o campi che permettono di definire, ad esempio, attributi privati con getter e setter pubblici. La differenza in Python è che gran parte dell'incapsulamento avviene tramite i magic method.
Per esempio, __setattr__ è una soluzione di incapsulamento che ci consente di definire un comportamento per l'assegnazione a un attributo a prescindere dalla sua esistenza. In altre parole, si possono definire regole per i cambiamenti dei valori degli attributi.
Nel codice sopra, abbiamo creato una classe chiamata Alphabet senza attributi, ma abbiamo detto a Python che volevamo mettere in maiuscolo qualsiasi attributo dell'istanza di classe che impostiamo.
Sappiamo che l'OOP può essere un po' ostica per alcuni lettori. Per metterti in pari con l'OOP in Python, dai un'occhiata al Python Programmer Track di DataCamp.
Magic method matematici
Un'altra categoria di magic method di Python sono i magic method matematici (noti anche come normali operatori aritmetici). Le espressioni sono create usando simboli speciali che chiamiamo "operatori" in Python. Usare tali operatori in un'espressione implica creare oggetti con magic method matematici. Il mancato rispetto di questa regola solleverà una TypeError.
Nel codice sopra, abbiamo provato a creare più istanze della classe Numbers e ad aggiungerle tra loro, cosa che ha generato un errore come previsto. Una soluzione potrebbe essere creare un metodo nella nostra classe per sommare i numeri, ma ciò ci impedirebbe di creare espressioni.
Una soluzione migliore è implementare un magic method __add__ come segue:
L'esempio di codice sopra ci consente solo di sommare due oggetti Numbers. Implementiamo un altro magic method matematico che ci permetta di moltiplicare un oggetto Numbers per un intero.
Nel codice sopra, abbiamo aggiunto un magic method __mul__ per permetterci di moltiplicare i numeri della nostra classe personalizzata per un intero.
Nota che l'oggetto Numbers compare a sinistra dell'operatore * – non è un caso. Mettiamolo a destra dell'operando e osserviamo cosa succede.
Python solleva una TypeError.
Il magic method __mul__ che abbiamo implementato copre solo il caso in cui l'oggetto Numbers si trovi sul lato sinistro dell'operatore *. Per estendere questa funzionalità, dobbiamo aggiungere il metodo inverso, __rmul__.
Ora possiamo creare un'espressione di moltiplicazione senza dover considerare da che lato dell'operando compare l'oggetto Numbers.
Conclusione
Il principio di base per sfruttare i magic method di Python resta lo stesso: creare una classe e sovrascrivere i magic method della classe object. I magic method in Python sono davvero tanti, quindi questo tutorial sarebbe lunghissimo se decidessimo di coprirli tutti singolarmente. Ti consigliamo vivamente di consultare la documentazione di Python per farti un'idea della portata completa dei magic method che puoi usare per migliorare le tue competenze di programmazione in Python.