Nel vasto mondo della programmazione Python, esiste un insieme di funzioni che spesso passano inosservate ai principianti, eppure hanno un’importanza significativa nell’ecosistema del linguaggio.
I metodi magici sono un insieme di metodi predefiniti in Python che forniscono speciali funzionalità sintattiche. Sono facilmente riconoscibili dai loro doppi trattini all’inizio e alla fine, come __init__, __call__, __len__
… ecc.
I metodi magici consentono agli oggetti personalizzati di comportarsi in modo simile ai tipi Python incorporati.
In questo articolo, ci concentreremo sulle potenti funzioni dunder. Esploreremo il loro scopo e discuteremo il loro utilizzo.
Che tu sia un principiante di Python o un programmatore esperto, questo articolo mira a fornire una comprensione completa delle funzioni Dunder, rendendo la tua esperienza di codifica Python più efficiente e piacevole.
Ricorda, la magia di Python non risiede solo nella sua semplicità e versatilità, ma anche nelle sue potenti funzionalità come le funzioni Dunder.
Forse la funzione dunder più basilare di tutte. Questo è il metodo magico che Python chiama automaticamente ogni volta che creiamo (o come suggerisce il nome, inizializziamo) un nuovo oggetto.__init__
class Pizza:
def __init__(self, size, toppings):
self.size = size
self.toppings = toppings
# Now let's create a pizza
my_pizza = Pizza('large', ['pepperoni', 'mushrooms'])
print(my_pizza.size) # This will print: large
print(my_pizza.toppings) # This will print: ['pepperoni', 'mushrooms']
In questo esempio viene creata una classe chiamata Pizza. Impostiamo la nostra funzione __init__ per includere i parametri da specificare al momento dell’inizializzazione, e li impostiamo come proprietà per il nostro oggetto personalizzato.
Qui, viene utilizzato per rappresentare l’istanza della classe. Quindi, quando scriviamo self.size = size, stiamo dicendo: “Ehi, questo oggetto pizza ha una dimensione di attributo size
, e voglio che sia qualsiasi dimensione che ho fornito quando ho creato l’oggetto”.
Questo è il metodo magico di Python che ci permette di definire una descrizione per il nostro oggetto personalizzato.
Quando stampi un oggetto o lo converti in una stringa usando str()
, Python controlla se hai definito un metodo __str__
per la classe di quell’oggetto.
In tal caso, utilizza tale metodo per convertire l’oggetto in una stringa.
Possiamo estendere il nostro esempio di Pizza per includere una funzione __str__
come segue:
class Pizza: def __init__(self, size, toppings): self.size = size self.toppings = toppings def __str__(self): return f"A {self.size} pizza with {', '.join(self.toppings)}" my_pizza = Pizza('large', ['pepperoni', 'mushrooms']) print(my_pizza) # This will print: A large pizza with pepperoni, mushrooms
__repr__
La funzione __str__ è più di un modo informale di descrivere le proprietà di un oggetto. D’altra parte, __repr__ viene utilizzato per fornire una descrizione più formale, dettagliata e univoca dell’oggetto personalizzato.
Se chiami repr()
su un oggetto o digiti semplicemente il nome dell’oggetto nella console, Python cercherà un metodo __repr__
.
Se __str__
non è definito, Python userà __repr__
come backup quando si tenta di stampare l’oggetto o convertirlo in una stringa. Quindi spesso è una buona idea definire almeno __repr__
, anche se non si definisce __str__
.
Ecco come potremmo definire __repr__
per il nostro esempio di pizza:
class Pizza:
def __init__(self, size, toppings):
self.size = size
self.toppings = toppings
def __repr__(self):
return f"Pizza('{self.size}', {self.toppings})"
my_pizza = Pizza('large', ['pepperoni', 'mushrooms'])
print(repr(my_pizza)) # This will print: Pizza('large', ['pepperoni', 'mushrooms'])
__repr__
ti dà una stringa che puoi eseguire come comando Python per ricreare l’oggetto pizza, mentre __str__
ti dà una descrizione più umana. Spero che ti aiuti a masticare un po ‘meglio questi metodi dunder!
In Python, sappiamo tutti che è possibile sommare i numeri usando l’operatore +
, come 3 + 5
.
Ma se vogliamo aggiungere istanze di qualche oggetto personalizzato?
La funzione dunder __add__
ci consente di fare proprio questo. Ci dà la possibilità di definire il comportamento dell’operatore +
sui nostri oggetti personalizzati.
Nell’interesse della coerenza, supponiamo che vogliamo definire il comportamento di +
sul nostro esempio di pizza. Diciamo che ogni volta che aggiungiamo due o più pizze insieme, combinerà automaticamente tutti i loro condimenti. Ecco come potrebbe apparire:
class Pizza:
def __init__(self, size, toppings):
self.size = size
self.toppings = toppings
def __add__(self, other):
if not isinstance(other, Pizza):
raise TypeError("You can only add another Pizza!")
new_toppings = self.toppings + other.toppings
return Pizza(self.size, new_toppings)
# Let's create two pizzas
pizza1 = Pizza('large', ['pepperoni', 'mushrooms'])
pizza2 = Pizza('large', ['olives', 'pineapple'])
# And now let's "add" them
combined_pizza = pizza1 + pizza2
print(combined_pizza.toppings) # This will print: ['pepperoni', 'mushrooms', 'olives', 'pineapple']
Analogamente al dunder __add__
, possiamo anche definire altre funzioni aritmetiche come __sub__
(per sottrazione usando l’operatore -
) e __mul__
(per la moltiplicazione usando l’operatore *
).
Questo metodo dunder ci consente di definire ciò che la funzione len()
deve restituire per i nostri oggetti personalizzati.
Python usa len()
per ottenere la lunghezza o la dimensione di una struttura di dati come un elenco o una stringa.
Nel contesto del nostro esempio, potremmo dire che la “lunghezza” di una pizza è il numero di condimenti che ha. Ecco come potremmo implementarlo:
class Pizza:
def __init__(self, size, toppings):
self.size = size
self.toppings = toppings
def __len__(self):
return len(self.toppings)
# Let's create a pizza
my_pizza = Pizza('large', ['pepperoni', 'mushrooms', 'olives'])
print(len(my_pizza)) # This will print: 3
Nel metodo __len__, restituiamo solo la lunghezza dell’elenco toppings
. Ora, len(my_pizza)
ci dirà quanti condimenti ci sono su my_pizza
.
Questo metodo dunder consente agli oggetti di essere iterabili, ovvero può essere utilizzato in un ciclo for.
Per fare ciò, dobbiamo anche definire la funzione __next__
, Questo viene utilizzato per definire il comportamento che dovrebbe restituire il valore successivo nell’iterazione. Inoltre, dovrebbe anche segnalare all’iterabile sull’evento che non ci sono più elementi nella sequenza. In genere otteniamo questo obiettivo sollevando un’eccezione StopIteration
.
Per il nostro esempio di pizza, supponiamo di voler iterare i condimenti. Potremmo rendere iterabile la nostra classe Pizza definendo un metodo __iter__
:
class Pizza:
def __init__(self, size, toppings):
self.size = size
self.toppings = toppings
def __iter__(self):
self.n = 0
return self
def __next__(self):
if self.n < len(self.toppings):
result = self.toppings[self.n]
self.n += 1
return result
else:
raise StopIteration
# Let's create a pizza
my_pizza = Pizza('large', ['pepperoni', 'mushrooms', 'olives'])
# And now let's iterate over it
for topping in my_pizza:
print(topping)
In questo caso, il ciclo for chiama __iter__
, che inizializza un contatore (self.n)
e restituisce l’oggetto pizza stesso (self)
.
Quindi, le chiamate for loop __next__
per ottenere ogni topping a turno.
Quando __next__
ha restituito tutti i condimenti, StopIteration
genera un’eccezione e il ciclo for ora sa che non ci sono più condimenti e quindi interromperà il processo di iterazione.
Ercole Palmeri
Excel fornisce un'ampia gamma di funzioni statistiche che eseguono calcoli dalla media, mediana e moda di base fino alla distribuzione…
Le tabelle pivot costituiscono una tecnica di analisi dei fogli di calcolo. Consentono a un principiante assoluto con zero esperienza…
Quello che segue è il secondo ed ultimo articolo di questa newsletter dedicato al rapporto tra Privacy e Copyright da…
Progetto ACTEA, ENEA e Sapienza Università di Roma metteranno a punto le nuove batterie calcio-ione. Le nuove batteria calcio-ione in alternativa a…
Oltre 900 chirurghi ortopedici del piede e della caviglia, operatori sanitari avanzati, specializzandi ortopedici e studenti di medicina hanno partecipato…
Secondo l’ultimo report Protolabs sulla robotica destinata alla produzione, quasi un terzo (32%) degli intervistati ritiene che nei prossimi anni…
CNH è fortemente impegnata nello sviluppo della propria tecnologia per rendere l’agricoltura più semplice, efficiente e sostenibile per i suoi…
La mossa strategica faciliterà uno sviluppo più veloce per l'adozione dell'ecosistema privato 5G per tutti i dispositivi digitali NTT svela…
Neuralink, la startup neurotecnologica di proprietà di Elon Musk, ha recentemente annunciato che inizierà a reclutare pazienti per il suo…
Questo è il primo di due articoli in cui affronto il delicato rapporto tra Privacy e Copyright da un lato,…