
Il parametro self in una classe in Python
Il parametro `self` rappresenta l'istanza della classe corrente in Python e puoi usarlo per accedere a variabili che appartengono alla classe.
In altre parole il parametro self è come un promemoria che aiuta a tenere traccia di quale specifico oggetto (istanza) sta operando all'interno della classe.
Perché usiamo `self`?
Il parametro`Self` è utile per permettere ai metodi di interagire con altri metodi e attributi della stessa istanza.
Lo usiamo per distinguere tra gli attributi/metodi interni della classe e le variabili locali nei metodi.
A cosa serve? Il parametro `self` è fondamentale per la programmazione orientata agli oggetti in Python, poiché permette alle classi di operare con i propri dati e comportamenti in modo organizzato. Grazie a `self`, ogni istanza mantiene il proprio stato e comportamento indipendentemente dalle altre istanze.
Per comprendere meglio, consideriamo un esempio pratico.
Immaginiamo di voler creare una classe per un libro. Un libro ha un titolo, un autore e può essere letto. Vediamo come potremmo strutturare questa classe:
class Libro:
def __init__(self, titolo, autore):
self.titolo = titolo
self.autore = autore
def mostra_informazioni(self):
print(f"Titolo: {self.titolo}, Autore: {self.autore}")
In questo esempio la classe `Libro` viene definita con il metodo `__init__`, che è il costruttore della classe.
Gli attributi `titolo` e `autore` sono preceduti da `self`, il che significa che questi attributi sono specifici per l'oggetto creato.
Quindi, in questo caso il parametro `self` qui si riferisce all'oggetto `Libro` che viene creato.
Il metodo mostra_informazioni() utilizza `self` per accedere agli attributi dell'oggetto. In questo modo può lavorare con i dati specifici dell'oggetto su cui viene chiamato il metodo.
Ad esempio, crea alcuni oggetti della classe `Libro`:
libro1 = Libro("Il Piccolo Principe", "Antoine de Saint-Exupéry")
libro2 = Libro("Fondazione", "Isaac Asimov")
Quando crei un nuovo oggetto, Python automaticamente passa il riferimento dell'oggetto stesso al parametro self dei suoi metodi.
Ora puoi utilizzare i metodi per accedere alle informazioni contenute in ciascun oggetto.
Quando chiami il metodo mostra_informazioni() sull'oggetto libro1, ti restituisce il titolo e l'autore del libro.
libro1.mostra_informazioni()
Titolo: Il Piccolo Principe, Autore: Antoine de Saint-Exupéry
Lo stesso avviene quando chiami il metodo sull'oggetto libro2.
libro2.mostra_informazioni()
Titolo: Fondazione, Autore: Isaac Asimov
Quindi, ogni volta che chiami un metodo come `mostra_informazioni` su `libro1`, `self` in quel metodo si riferisce a `libro1`.
Quando, invece, chiami `leggi` su `libro2`, `self` si riferisce a `libro2`.
Cosa accade se non utilizzi self?
Se non utilizzi `self` quando definisci attributi o metodi all'interno di una classe in Python, finirai per avere comportamenti diversi, e in molti casi, risultati indesiderati.
Ad esempio, supponiamo di definire una classe senza usare `self` per gli attributi:
class Libro:
def __init__(self, titolo, autore):
titolo = titolo
autore = autore
def mostra_informazioni(self):
print(f"Titolo: {titolo}, Autore: {autore}")
libro1 = Libro("Il Piccolo Principe", "Antoine de Saint-Exupéry")
libro2 = Libro("Fondazione", "Isaac Asimov")
libro1.mostra_informazioni()
In questo esempio, `titolo` e `autore` sono trattati come variabili locali all'interno del costruttore `__init__`.
Queste variabili sono disponibili solo durante l'esecuzione di `__init__` e non sono memorizzate come attributi dell'oggetto.
Di conseguenza, quando tenti di accedere a queste variabili nel metodo `mostra_informazioni`, Python solleva un'eccezione `NameError` perché `titolo` e `autore` non sono riconosciuti al di fuori di `__init__`.
NameError: name 'titolo' is not defined
Ora vediamo cosa accade se definisci un metodo senza usare `self`.
class Libro:
def __init__(self, titolo, autore):
self.titolo = titolo
self.autore = autore
def mostra_informazioni():
print("Questo è un libro.")
libro1 = Libro("Il Piccolo Principe", "Antoine de Saint-Exupéry")
libro2 = Libro("Fondazione", "Isaac Asimov")
libro1.mostra_informazioni()
In questo caso il metodo non sarà legato all'istanza dell'oggetto:
Questo vuol dire che non potrai chiamarlo sull'istanza dell'oggetto perché Python si aspetta che il primo parametro di un metodo di istanza sia sempre una referenza all'oggetto stesso (tipicamente `self`).
Se provi a chiamare `mostra_informazioni` su un'istanza della classe `Libro`, otterrai un `TypeError`.
TypeError: Libro.mostra_informazioni() takes 0 positional arguments but 1 was given
Questo accade perché Python tenta di passare automaticamente l'oggetto istanza come primo argomento, e il metodo non è configurato per accettarlo.
Quindi, l'uso di `self` è essenziale per definire attributi e metodi che operano con le istanze specifiche di una classe.
Omettere `self` può portare a errori che impediscono il corretto funzionamento della classe, poiché le variabili locali saranno inaccessibili fuori dai loro metodi di definizione, e i metodi che non accettano `self` non potranno interagire con gli attributi dell'istanza.