Classi e oggetti Python: Tutorial OOP con esempi reali
Impara Python orientato agli oggetti costruendo qualcosa di reale. Crea classi, comprendi self e __init__, condividi il comportamento con l’ereditarietà, proteggi i dati con proprietà e scopri quando una classe è lo strumento sbagliato.
- Una classe è un progetto e un oggetto è qualcosa costruito a partire da esso.
__init__imposta ogni nuovo oggetto eselfsi riferisce a quell’oggetto.- Gli attributi impostati sulla classe sono condivisi. Gli attributi impostati su
selfappartengono a un oggetto. - Utilizzare
@dataclassper le classi che contengono dati e preferire funzioni semplici quando non c’è uno stato da mantenere.
Man mano che uno script cresce, finisci per passare lo stesso gruppo di variabili tra le funzioni e diventa difficile dire quali dati appartengono a quale logica. Classi e oggetti Python risolvono questo problema raggruppando dati e comportamenti in un’unica unità.
In questo tutorial creiamo passo dopo passo un piccolo conto bancario e aggiungiamo ogni idea OOP solo quando risolve un problema. Abbiamo eseguito ogni esempio su Python 3.13 e l’output mostrato proviene da quell’esecuzione. Se non conosci il linguaggio, leggi prima il nostro tutorial Python per principianti.
Cosa sono le classi e gli oggetti?
Una classe descrive cos’è qualcosa e cosa può fare. Un oggetto, chiamato anche istanza, è un oggetto specifico creato da quella descrizione. “Account” è una classe, mentre l’account di Asha e l’account di Ben sono due oggetti.
| Termine | Significato | Esempio |
|---|---|---|
| Classe | Il progetto | Conto |
| Oggetto o istanza | Ne è derivata una cosa | a = Conto("Asha") |
| Attributo | Dati sull’oggetto | a.balance |
| Metodo | Una funzione sulla classe | a.deposit(50) |
Hai sempre usato oggetti. In Python, stringhe, elenchi e persino funzioni sono oggetti, motivo per cui puoi scrivere "hello".upper().
La tua prima lezione
class Account:
def __init__(self, owner, balance=0):
self.owner = owner
self.balance = balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("amount must be positive")
self.balance += amount
return self.balance
a = Account("Asha", 100)
b = Account("Ben")
a.deposit(50)
print(a.balance, b.balance)
# 150 0
__init__ viene eseguito automaticamente ogni volta che crei un oggetto e imposta lo stato iniziale. Il deposito in a non ha toccato b, perché ogni oggetto ha i propri dati. Si noti che il metodo protegge anche il saldo da un valore errato. La nostra guida alla gestione delle eccezioni Python spiega raise in modo più approfondito.
Cos’è il sé?
self è semplicemente l’oggetto su cui sta lavorando un metodo. Quando scrivi a.deposit(50), Python chiama effettivamente Account.deposit(a, 50), passando l’oggetto come primo argomento. Ecco come una definizione di metodo può servire ogni oggetto.
Il nome self è una convenzione forte piuttosto che una parola chiave, ma usalo sempre. Dimenticarlo nella definizione di un metodo è l’errore più comune per i principianti e produce un messaggio confuso sul numero di argomenti.
Attributi di classe e attributi di istanza
Un attributo impostato direttamente nel corpo della classe è condiviso da tutti gli oggetti. Un set su self appartiene solo a quell’oggetto. Questo esempio mostra come si comportano le ricerche:
class Account:
interest_rate = 0.04 # class attribute
def __init__(self, owner, balance=0):
self.owner = owner # instance attribute
self.balance = balance
a = Account("Asha", 100)
b = Account("Ben")
print(a.interest_rate, b.interest_rate) # 0.04 0.04
Account.interest_rate = 0.05
print(a.interest_rate, b.interest_rate) # 0.05 0.05
a.interest_rate = 0.09
print(a.interest_rate, b.interest_rate, Account.interest_rate)
# 0.09 0.05 0.05
Quest’ultima riga sorprende le persone. L’assegnazione tramite a non ha modificato il valore condiviso. Ha creato un nuovo attributo di istanza su a che nasconde quello di classe. Python esamina prima l’oggetto, poi la classe.
Metodi speciali (dunder).
I metodi con doppi caratteri di sottolineatura consentono ai tuoi oggetti di funzionare con le funzionalità integrate di Python. Senza di essi, la stampa di un account mostra un indirizzo di memoria inutile. L’aggiunta di due dà una forma leggibile:
def __str__(self):
return f"{self.owner}: {self.balance}"
def __repr__(self):
return f"Account({self.owner!r}, {self.balance})"
print(a) # Asha: 150
print([a, b]) # [Account('Asha', 150), Account('Ben', 0)]
| Metodo | Innescato da |
|---|---|
__init__ |
Creare un oggetto |
__str__ |
print(obj), str(obj) |
__repr__ |
Debug o visualizzazione in un elenco |
__eq__ |
un == b |
__len__ |
len(obj) |
__add__ |
a+b |
Eredità
L’ereditarietà consente a una nuova classe di riutilizzarne una esistente e di modificare solo ciò che differisce. Qui, Savings è un Account con un’impostazione aggiuntiva:
class Savings(Account):
def __init__(self, owner, balance=0, limit=3):
super().__init__(owner, balance)
self.limit = limit
def __str__(self):
return f"{super().__str__()} (savings)"
s = Savings("Chitra", 500)
s.deposit(100)
print(s, isinstance(s, Account), s.limit)
# Chitra: 600 (savings) True 3
super() chiama la versione del genitore, quindi la logica di installazione non viene ripetuta. deposit è stato ereditato così com’era e __str__ è stato sovrascritto per aggiungere un’etichetta. Utilizzare l’ereditarietà solo per una relazione reale “è un”. Se una classe ha semplicemente bisogno di qualcosa, come un’auto che necessita di un motore, assegnale quell’oggetto come attributo. Questo è noto come composizione e di solito è più flessibile delle catene di ereditarietà profonde.
Polimorfismo
Il polimorfismo significa che oggetti diversi possono rispondere alla stessa chiamata di metodo a modo loro. Non è necessario che il codice chiamante conosca il tipo esatto:
class Square:
def __init__(self, side):
self.side = side
def area(self):
return self.side ** 2
class Circle:
def __init__(self, radius):
self.radius = radius
def area(self):
return round(3.14159 * self.radius ** 2, 2)
for shape in [Square(3), Circle(2)]:
print(type(shape).__name__, shape.area())
# Square 9
# Circle 12.57
Queste due classi non condividono nemmeno un genitore. A Python interessa solo che l’oggetto abbia un metodo area, un approccio noto come ducktyping. L’aggiunta di un Triangle in un secondo momento non richiederebbe alcuna modifica al loop.
Incapsulamento e proprietà
Python non ha attributi veramente privati e si basa invece su convenzioni. Un singolo carattere di sottolineatura, come in _price, dice agli altri sviluppatori “questo è interno, per favore non toccarlo”. Per controllare i valori quando sono impostati, utilizza una property, che sembra un semplice attributo dall’esterno:
class Product:
def __init__(self, price):
self.price = price
@property
def price(self):
return self._price
@price.setter
def price(self, value):
if value < 0:
raise ValueError("price cannot be negative")
self._price = value
p = Product(100)
p.price = 150
print(p.price) # 150
p.price = -5 # ValueError: price cannot be negative
Ciò significa che puoi iniziare con un attributo semplice e aggiungere la convalida in seguito senza modificare alcun codice che utilizza la classe. Quindi non scrivere i metodi get_price() e set_price() per abitudine, come potresti fare in Java. La @ sintassi qui è un decoratore, che spiegheremo in Spiegazione dei decoratori Python.
Metodi di classe e metodi statici
class Temperature:
def __init__(self, celsius):
self.celsius = celsius
@classmethod
def from_fahrenheit(cls, f):
return cls(round((f - 32) * 5 / 9, 1))
@staticmethod
def is_freezing(celsius):
return celsius <= 0
Temperature.from_fahrenheit(212).celsius # 100.0
Temperature.is_freezing(-3) # True
| Digitare | Primo argomento | Usalo per |
|---|---|---|
| Metodo di istanza | sé |
Lavorare con i dati di un oggetto |
@classmethod |
cls |
Costruttori alternativi |
@staticmethod |
Nessuno | Aiutanti legati alla classe |
Classi dati
Quando una classe contiene principalmente dati, scrivere __init__, __repr__ e __eq__ a mano è noioso. @dataclass li genera dalle annotazioni di tipo:
from dataclasses import dataclass, field
@dataclass
class Item:
name: str
price: int
tags: list = field(default_factory=list)
print(Item("Pen", 10))
print(Item("Pen", 10) == Item("Pen", 10))
# Item(name='Pen', price=10, tags=[])
# True
Suggerimento: Non tutto ha bisogno di una lezione. Se non ha uno stato e un solo comportamento, una funzione semplice è più semplice. Per ricerche semplici, un dizionario potrebbe essere sufficiente. Raggiungere una classe quando i dati e le regole che li proteggono chiaramente vanno di pari passo.
Errori comuni
Utilizzando un attributo di classe mutabile
Questo è un bug classico. L’elenco è definito nella classe, quindi tutti i carrelli lo condividono:
class Cart:
items = [] # shared by every cart!
def add(self, item):
self.items.append(item)
c1, c2 = Cart(), Cart()
c1.add("pen")
print(c2.items)
# ['pen']
Crealo in __init__ con self.items = [], in modo che ogni oggetto abbia il proprio elenco.
Altri errori comuni
- Dimenticare
self. Scrivereself.balance, nonbalance, all’interno dei metodi. - Dimenticare
super().__init__(). Il bambino perde quindi gli attributi impostati dal genitore. - Creare classi enormi. Una classe che fa tutto è difficile da testare. Dividilo per responsabilità.
- Ereditarietà profonda. Due livelli sono generalmente sufficienti e la composizione è spesso più chiara.
- Non scrivere test. Le classi con regole sono facili da testare, come mostra il nostro tutorial pytest utilizzando un piccolo carrello.
Considerazioni finali
Python orientato agli oggetti si riduce al raggruppamento dei dati con il comportamento che li protegge. Inizia con __init__, metodi e __str__, quindi aggiungi ereditarietà e proprietà quando incontri un problema che risolvono. Come passo successivo, prendi uno script che passi le stesse poche variabili ovunque e trasformale in un’unica piccola classe.
Domande frequenti
Qual è la differenza tra una classe e un oggetto?
Una classe è la definizione, o progetto. Un oggetto è un’istanza specifica creata da esso, con i propri dati. Una classe può creare molti oggetti.
Cosa fa __init__ in Python?
È l’inizializzatore, che viene eseguito automaticamente quando crei un oggetto. Di solito imposta gli attributi iniziali dell’oggetto dagli argomenti che passi.
Cos’è il sé in Python?
self si riferisce all’oggetto su cui viene chiamato un metodo. Python lo passa automaticamente e consente al metodo di leggere e modificare gli attributi di quell’oggetto.
Quali sono i quattro pilastri dell’OOP?
Sono incapsulamento, astrazione, ereditarietà e polimorfismo. Insieme, ti aiutano a raggruppare i dati con il comportamento, nascondere i dettagli e riutilizzare il codice.
Quando dovrei usare una classe invece di una funzione?
Utilizza una classe quando i dati e il comportamento si uniscono in diverse operazioni. Per un’operazione stateless, una funzione semplice è più semplice e facile da testare.
Continua a imparare
Hai bisogno di aiuto con test, WordPress o SEO?
Aiutiamo i team a fornire software migliore e a far crescere i loro siti. Raccontaci a cosa stai lavorando e ti suggeriremo chiaramente il prossimo passo.
Altre guide su test, intelligenza artificiale e sviluppo moderno
Ti è piaciuto questo articolo? Scegli un argomento e passa direttamente ai nostri tutorial più recenti.
Spiegazione delle allucinazioni dell'intelligenza artificiale: perché i modelli linguistici inventano le cose e come ridurle
Spiegazione delle allucinazioni dell'intelligenza artificiale: cosa sono, perché i modelli linguistici le producono, tipi comuni, come ridurle con b…
Leggi l'articolo →DevOpsSpiegazione delle variabili d'ambiente: file .env, segreti e configurazione eseguiti correttamente
Variabili d'ambiente spiegate con esempi Python che abbiamo eseguito: lettura e impostazione, perché ogni valore è una stringa, file .env, ereditari…
Leggi l'articolo →Sviluppo softwareSpiegazione della limitazione della velocità API: algoritmi, intestazioni e gestione degli errori 429
La limitazione della velocità dell'API spiegata con una simulazione che abbiamo eseguito: bucket di token, finestra fissa, finestra scorrevole, risp…
Leggi l'articolo →Automazione dei testDerisione in Python: unittest.mock, patch e gli errori che fanno mentire i test
Mocking in Python con unittest.mock, testato: Mock e return_value, side_effect, patch dove viene utilizzato un nome, specifiche e autospec, date moc…
Leggi l'articolo →Test del softwareSpiegazione della copertura del codice: copertura di linea o di filiale e cosa significa realmente il 100%.
Copertura del codice spiegata con una vera esecuzione di cover.py: copertura di linea, ramo e condizione, lettura di un rapporto, perché la copertur…
Leggi l'articolo →Database e SQLDELETE vs TRUNCATE vs DROP in SQL: differenze, rollback e quando utilizzarli
DELETE vs TRUNCATE vs DROP spiegato con SQL testato: cosa rimuove, rollback, trigger, reimpostazione dell'identità, velocità e come differiscono Pos…
Leggi l'articolo →Database e SQLSpiegazione delle visualizzazioni SQL: crea, utilizza ed evita le insidie, con esempi
Viste SQL spiegate con le query che abbiamo eseguito: creazione di una vista, risultati in tempo reale, nascondere colonne, prestazioni, viste aggio…
Leggi l'articolo →Sviluppo softwareInterfaccia TypeScript e tipo: differenze reali, testate con il compilatore
Interfaccia TypeScript vs tipo, verificata con il vero compilatore: cosa possono fare entrambi, cosa può fare solo uno, fusione delle dichiarazioni,…
Leggi l'articolo →Sviluppo softwareSpiegazione di Python *args e **kwargs: funzioni flessibili con esempi chiari
Python *args e **kwargs spiegati con il codice che abbiamo eseguito: compressione e decompressione, ordine dei parametri, argomenti solo per parole …
Leggi l'articolo →Sviluppo softwareFunzioni Lambda Python: sintassi, usi reali e quando non usarli
Funzioni lambda Python spiegate con il codice che abbiamo eseguito: sintassi, ordinamento con chiave, mappa e filtro, chiusure, trap dell'associazio…
Leggi l'articolo →Intelligenza artificialeCosa sono gli agenti AI? Come funzionano, con un semplice ciclo di agenti che puoi eseguire
Cosa sono gli agenti IA? Una semplice guida al ciclo dell'agente, agli strumenti, alla memoria e ai guardrail, con un piccolo ciclo Python che abbia…
Leggi l'articolo →DevOpsMonitoraggio vs osservabilità: la vera differenza, con log, metriche e tracce
Spiegazione del monitoraggio e dell'osservabilità: errori noti e sconosciuti, log, metriche e tracce, una procedura dettagliata sugli incidenti di p…
Leggi l'articolo →DevOpsVolumi Docker e montaggi di associazione: mantenere i dati del contenitore nel modo giusto
Volumi Docker e montaggi di collegamento spiegati: perché i dati del contenitore scompaiono, volumi denominati, montaggi di collegamento, tmpfs, ese…
Leggi l'articolo →Automazione dei testTDD vs BDD: differenze chiave, una caratteristica costruita in entrambi i modi e quando utilizzarli ciascuno
TDD vs BDD spiegato con una funzione di sconto costruita in entrambi i modi: refactoring rosso-verde con il codice che abbiamo eseguito, scenari "Da…
Leggi l'articolo →Test del softwareTest di accettazione da parte dell'utente (UAT): processo, lista di controllo ed esempi reali
Spiegazione del test di accettazione dell'utente: chi lo esegue, in cosa differisce dal QA, un processo in sette fasi, un modello di test case UAT, …
Leggi l'articolo →Database e SQLSpiegazione dei valori SQL NULL: IS NULL, COALESCE, NULLIF e le trappole da evitare
Valori SQL NULL spiegati con le query che abbiamo eseguito: logica a tre valori, IS NULL, COALESCE, NULLIF, come aggregazioni, join e ordinamento tr…
Leggi l'articolo →Database e SQLIstruzione SQL CASE WHEN: sintassi, esempi reali ed errori comuni
SQL CASE WHEN spiegato con le query che abbiamo eseguito: moduli semplici e cercati, ordine delle condizioni, pivot con SUM, trucchi COUNT, ordiname…
Leggi l'articolo →Sviluppo softwareCos'è il JWT? Token Web JSON spiegati con un esempio funzionante
Cos'è il JWT? Spiegazione dei token Web JSON: le tre parti, un token creato e manomesso nel codice che abbiamo eseguito, JWT e sessioni, archiviazio…
Leggi l'articolo →Sviluppo softwareSpiegazione del loop di eventi JavaScript: stack di chiamate, microtask e timer con esempi
Il ciclo di eventi JavaScript spiegato con il codice che abbiamo eseguito: stack di chiamate, code di attività e microtask, perché setTimeout 0 non …
Leggi l'articolo →Sviluppo softwareSpiegazione dei generatori Python e del rendimento: risparmia memoria con esempi reali
Generatori Python e rendimento spiegati con il codice che abbiamo eseguito: come vengono messi in pausa e ripresi, misurato il risparmio di memoria,…
Leggi l'articolo →Intelligenza artificialeCosa sono gli incorporamenti? I vettori e la somiglianza del coseno spiegati semplicemente
Cosa sono gli incorporamenti? Una guida in linguaggio semplice ai vettori, alla similarità del coseno e alla ricerca semantica, con un piccolo esemp…
Leggi l'articolo →DevOpsDistribuzione blu-verde rispetto a quella canaria: differenze, compromessi e come scegliere
Spiegazione della distribuzione blu-verde e canary: come funziona ciascuna, costi, rischi e rollback, bucket utente stabile che abbiamo testato, mig…
Leggi l'articolo →Automazione dei testTest instabili: quali sono le cause e come risolverli definitivamente
Test instabili spiegati con demo che abbiamo eseguito: le cause principali, come confermarne e diagnosticarne uno, soluzioni adeguate per tempistich…
Leggi l'articolo →Test del softwareTest di carico e test di stress: differenze, metriche ed esempi k6
Spiegazione del test di carico e dello stress test: cosa dimostra ciascuno, test di picco e di assorbimento, le metriche che contano, perché le medi…
Leggi l'articolo →Test del softwareCaso di test e scenario di test: differenze chiave, esempi e quando utilizzarli
Spiegazione del caso di test e dello scenario di test: definizioni chiare, una tabella affiancata, una funzione di reimpostazione della password pre…
Leggi l'articolo →Database e SQLOttimizzazione delle query SQL: leggi i piani di esecuzione e correggi query lente, con tempistiche
Ottimizzazione delle query SQL testata su un milione di righe: leggi i piani di esecuzione, aggiungi gli indici corretti, correggi filtri non aggior…
Leggi l'articolo →Database e SQLSQL UNION vs UNION ALL: differenze, esempi e prestazioni testate
SQL UNION vs UNION ALL spiegati con le query che abbiamo eseguito: duplicati, regole seguite da entrambi, un vero bug di dati, prestazioni misurate,…
Leggi l'articolo →Sviluppo softwareTutorial sull'API di recupero JavaScript: GET, POST, gestione degli errori e timeout
Un tutorial sull'API JavaScript Fetch testato su un server locale: GET e POST, perché 404 non genera eccezioni, un helper riutilizzabile, stringhe d…
Leggi l'articolo →Sviluppo softwareGestione dei file Python: lettura, scrittura, CSV, JSON e pathlib con esempi
Gestione dei file Python spiegata con il codice che abbiamo eseguito: modalità aperte, con, lettura di file di grandi dimensioni, CSV, JSON, pathlib…
Leggi l'articolo →Sviluppo softwareClassi e oggetti Python: tutorial OOP con esempi reali
Classi e oggetti Python spiegati con il codice che abbiamo eseguito: __init__, metodi, attributi di classe e istanza, ereditarietà, proprietà, metod…
Leggi l'articolo →Intelligenza artificialeChe cos'è un modello linguistico di grandi dimensioni? Come funzionano i LLM, spiegato senza esagerazioni
Cos’è un modello linguistico ampio? LLM spiegati in un linguaggio semplice: token, incorporamenti, attenzione, formazione, finestre di temperatura e…
Leggi l'articolo →DevOpsComandi Linux per principianti: la guida essenziale del terminale con esempi
Comandi Linux per principianti, raggruppati per attività: navigazione, file, visualizzazione log, grep, pipe, permessi, processi e archivi, con un e…
Leggi l'articolo →Automazione dei testSelenio vs drammaturgo: differenze chiave, codice a confronto e quale scegliere
Selenium vs Playwright a confronto: architettura, attesa, supporto per browser e linguaggio, debug, lo stesso test in entrambi gli strumenti, consig…
Leggi l'articolo →Test del softwarePartizionamento di equivalenza: tecnica di progettazione dei test spiegata con esempi pratici
Spiegazione del partizionamento di equivalenza: come trovare partizioni valide e non valide, esempi funzionanti per età, password e coupon, test che…
Leggi l'articolo →Test del softwareGravità vs priorità nel test del software: differenze, matrice ed esempi reali
Spiegazione della gravità e della priorità nei test del software: definizioni chiare, una matrice a quattro vie con esempi, scale di livello, chi im…
Leggi l'articolo →Database e SQLEsercitazione sulle sottoquery SQL: tipi, sottoquery correlate ed EXISTS con esempi
Un tutorial sulle sottoquery SQL con le query che abbiamo eseguito: sottoquery scalari, IN, FROM e SELECT, sottoquery correlate, EXISTS, trap NOT IN…
Leggi l'articolo →Database e SQLSpiegazione di transazioni SQL e ACID: COMMIT, ROLLBACK e livelli di isolamento
Transazioni SQL e ACID spiegate con un bonifico bancario eseguito: COMMIT, ROLLBACK, punti di salvataggio, blocchi, livelli di isolamento, letture s…
Leggi l'articolo →Sviluppo softwareGit merge vs rebase: differenze, esempi e quando usare ciascuno
Git merge vs rebase spiegato con output reale del log, una tabella di confronto, la regola d'oro del rebase e un flusso di lavoro sicuro per i team.
Leggi l'articolo →Sviluppo softwareList comprehension in Python: sintassi, esempi e quando evitarla
List comprehension in Python spiegata: sintassi, filtri, if-else, cicli annidati, tempi misurati e i casi in cui un normale ciclo for è meglio.
Leggi l'articolo →Database e SQLSQL JOIN spiegati con esempi (Inner, Left, Right, Full)
Capisci i JOIN SQL passo dopo passo con tabelle e query di esempio: INNER, LEFT, RIGHT, FULL, CROSS e SELF, con errori comuni e consigli sulle prest…
Leggi l'articolo →