Classi e oggetti Python: tutorial OOP con esempi reali

  1. Home
  2. Blog
  3. Sviluppo software

Sviluppo software

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.

10 min di lettura
Classi e oggetti Python: tutorial OOP con esempi reali

Punti chiave

  • Una classe è un progetto e un oggetto è qualcosa costruito a partire da esso.
  • __init__ imposta ogni nuovo oggetto e self si riferisce a quell’oggetto.
  • Gli attributi impostati sulla classe sono condivisi. Gli attributi impostati su self appartengono a un oggetto.
  • Utilizzare @dataclass per 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. Scrivere self.balance, non balance, 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

Lavora con Stack Quora

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.

Continua a leggere

Altre guide su test, intelligenza artificiale e sviluppo moderno

Ti è piaciuto questo articolo? Scegli un argomento e passa direttamente ai nostri tutorial più recenti.

Intelligenza artificiale

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 →
DevOps

Spiegazione 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 software

Spiegazione 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 test

Derisione 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 software

Spiegazione 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 SQL

DELETE 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 SQL

Spiegazione 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 software

Interfaccia 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 software

Spiegazione 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 software

Funzioni 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 artificiale

Cosa 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 →
DevOps

Monitoraggio 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 →
DevOps

Volumi 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 test

TDD 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 software

Test 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 SQL

Spiegazione 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 SQL

Istruzione 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 software

Cos'è 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 software

Spiegazione 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 software

Spiegazione 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 artificiale

Cosa 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 →
DevOps

Distribuzione 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 test

Test 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 software

Test 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 software

Caso 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 SQL

Ottimizzazione 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 SQL

SQL 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 software

Tutorial 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 software

Gestione 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 software

Classi 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 artificiale

Che 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 →
DevOps

Comandi 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 test

Selenio 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 software

Partizionamento 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 software

Gravità 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 SQL

Esercitazione 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 SQL

Spiegazione 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 software

Git 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 software

List 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 SQL

SQL 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 →