Articoli

Python e i metodi avanzati, le dunder functions per una migliore programmazione

Python è un fantastico linguaggio di programmazione e, come evidenziato da GitHub, è anche il secondo linguaggio più popolare nel 2022.

I vantaggi più interessanti di Python sono la grande comunità di programmatori.

Sembra che Python abbia un pacchetto per qualsiasi caso d’uso.

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

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.

__init__

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”.

__str__ e __repr__

__Str__

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!

__add__

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 *).

__len__

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.

__iter__

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

Newsletter sull’Innovazione
Non perderti le notizie più importanti sull'Innovazione. Iscriviti per riceverle via e-mail.
Tags: python

Articoli recenti

Veeam presenta il supporto più completo per il ransomware, dalla protezione alla risposta e al ripristino

Coveware by Veeam continuerà a fornire servizi di risposta agli incidenti di cyber-estorsione. Coveware offrirà funzionalità di forensics e remediation…

23 Aprile 2024

Rivoluzione Verde e Digitale: Come la Manutenzione Predittiva sta Trasformando il Settore Oil & Gas

La manutenzione predittiva sta rivoluzionando il settore dell'oil & gas, con un approccio innovativo e proattivo alla gestione degli impianti.…

22 Aprile 2024

L’autorità antitrust del Regno Unito lancia l’allarme BigTech su GenAI

La CMA del Regno Unito ha lanciato un avvertimento circa il comportamento delle Big Tech sul mercato dell’intelligenza artificiale. La…

18 Aprile 2024

Casa Green: rivoluzione energetica per un futuro sostenibile in Italia

Il Decreto "Case Green", formulato dall'Unione Europea per potenziare l'efficienza energetica degli edifici, ha concluso il suo iter legislativo con…

18 Aprile 2024