
I metodi in una classe Python
I metodi di una classe sono funzioni che definiscono il comportamento degli oggetti creati con la classe o della classe stessa.
Cos'è una classe? In Python, una classe può essere vista come un modo per creare oggetti che condividono le stesse proprietà e comportamenti.
In Python, gli attributi di una classe possono essere generalmente divisi in due grandi categorie: metodi e proprietà.
- Metodi (attributi chiamabili)
Sono funzioni definite all'interno di una classe e, come hai detto, sono "chiamabili". Ciò significa che possono essere invocati o eseguiti, poiché sono funzioni. Operano sui dati dell'oggetto e possono anche manipolare lo stato della classe o dell'istanza. - Proprietà (attributi non chiamabili)
Questi sono gli attributi non chiamabili che contengono dati o informazioni. Sono spesso definiti nel metodo __init__ di una classe e possono essere utilizzati per mantenere lo stato dell'oggetto. Esempi comuni di proprietà possono essere nome, marca, modello ecc., in una classe che rappresenta un prodotto o un veicolo.
In generale puoi vedere i metodi come attributi chiamabili della classe.
In realtà Python ammette anche una terza categoria intermedia detta delle "proprietà chiamabili" che ti permette di trattare i metodi come attributi non chiamabili. Ma di questo ne parleremo in una lezione a parte.
Il linguaggio Python ammette diversi tipi di metodi: di istanza, di classe e statici.
I metodi di istanza e di classe sono legati rispettivamente all'istanza o alla classe e sono detti "bound methods".
Viceversa, i metodi statici non hanno un riferimento né all'istanza, né alla classe.
Metodi di istanza
I metodi di istanza operano sui dati di un singolo oggetto creato dalla classe.
Questi metodi hanno bisogno di un riferimento all'oggetto stesso (`self`) per manipolare i dati dell'oggetto.
class Automobile:
def __init__(self, marca, modello):
self.marca = marca
self.modello = modello
def descrizione(self):
return f"{self.marca} {self.modello}"
# Creazione di un'istanza
auto = Automobile("Fiat", "500")
print(auto.descrizione())
Fiat 500
In questo esempio, `descrizione` è un metodo di istanza.
Utilizza `self` per accedere alle proprietà dell'oggetto e restituire una stringa che descrive l'automobile.
Metodi di classe
I metodi di classe lavorano con la classe stessa piuttosto che con l'istanza.
Sono marcati con il decoratore `@classmethod` e prendono come primo parametro la classe, di solito chiamata `cls`.
class Automobile:
tasso_tasse = 1.20
@classmethod
def tassa(cls, prezzo):
return cls.tasso_tasse * prezzo
# Uso del metodo di classe
print(Automobile.tassa(15000))
18000
In questo caso, `tassa` è un metodo di classe che calcola le tasse basate su un tasso definito a livello di classe.
Puoi accedere a questo metodo direttamente dalla classe, senza creare un'istanza.
Metodi statici
I metodi statici sono simili ai metodi di classe ma non prendono automaticamente un riferimento né all'istanza (`self`) né alla classe (`cls`).
Sono utili per funzionalità che non necessitano di accedere agli attributi dell'oggetto o della classe.
Si marcano con `@staticmethod`.
class Automobile:
@staticmethod
def valida_targa(targa):
return len(targa) == 7
# Uso del metodo statico
print(Automobile.valida_targa("1234567"))
True
Questo metodo statico può essere chiamato per verificare se una targa ha il numero corretto di caratteri, indipendentemente da qualsiasi specifica istanza o classe.
Quando progetti una classe, pensa a quali operazioni sono strettamente collegate alle istanze (metodi di istanza), quali appartengono alla classe nel suo insieme (metodi di classe), e quali operazioni sono genericamente utili e non dipendono dall'istanza o dalla classe stessa (metodi statici). In questo modo puoi strutturare il codice in modo chiaro e logico, rendendo più facile la manutenzione e la comprensione del programma.
Le variabili locali nei metodi
Le variabili create all'interno dei metodi sono variabili locali a quei metodi.
Non sono accessibili né dall'esterno del metodo né da altre istanze/metodi, a meno che non vengano definiti come attributi di istanza o classe.
Questo significa che le variabili nei metodi esistono solo durante l'esecuzione del metodo e non sono visibili o accessibili fuori dal metodo stesso. Questo isolamento aiuta a mantenere i metodi indipendenti l'uno dall'altro e consente l'incapsulamento. L'incapsulamento è uno dei principi fondamentali della programmazione orientata agli oggetti, perché protegge lo stato interno di un oggetto (le sue variabili) dall'accesso diretto esterno ed espone solo ciò che è necessario tramite metodi pubblici.
Ad esempio, questo script contiene una classe e alcune variabili di diverso tipo.
class Car:
message="welcome" # Attributo di classe
def __init__(self, color):
self.color = color # Attributo di istanza
self.message="hello"
def display_info(self):
message = f"This car is {self.color}." # Variabile locale
return message
# Creazione di istanze della classe Car
car1 = Car("red")
message="welcome" # variabile globale
In questo script ci sono ben quattro variabili con lo stesso nome "message": una variabile locale nel metodo, un attributo di istanza, un attributo di classe e una variabile globale.
Questo accade perché in Python, ci sono diversi "scope" o ambiti in cui le variabili possono esistere.
La variabile locale "message" è visibile solo quando chiami il metodo display_info(self) che la contiene.
print(car1.display_info())
This car is red.
Se invece digiti car1.message Python accede all'attributo di istanza "hello".
print(car1.message)
hello
Ricorda che quando un metodo tenta di accedere a variabili che non sono locali, prima cerca nelle variabili di istanza, quelle accessibili tramite self, poi nelle variabili di classe, e infine nelle variabili globali.
Se la variabile non viene trovata in nessuno di questi ambiti, Python solleva un NameError, indicando che la variabile non è stata definita.
Un errore comune per i principianti è tentare di accedere direttamente a una variabile di classe dentro un metodo senza qualificarla con il nome della classe o self (per le variabili di istanza). Questo porta a un NameError a meno che non ci sia una variabile locale o globale con lo stesso nome.