W3docs

Classi e Oggetti in Python

Scopri come funzionano classi e oggetti in Python: definisci classi, usa __init__, crea istanze, gestisci attributi e metodi e comprendi l'ereditarietà.

Python è un linguaggio di programmazione orientato agli oggetti (OOP), il che significa che organizza il codice attorno agli oggetti anziché alle sole funzioni. Una classe è il modello che descrive quali dati contiene un object e cosa può fare. Un object è un'istanza specifica creata da quel modello.

Questo capitolo tratta:

  • Cosa sono le classi e gli oggetti e perché sono importanti
  • Come definire una classe con __init__, attributi di istanza e metodi
  • Attributi di classe versus attributi di istanza
  • Come creare e utilizzare gli oggetti
  • Come modificare ed eliminare attributi
  • Come verificare i tipi di oggetti con isinstance()
  • Una prima panoramica sull'ereditarietà

Per un approfondimento sull'ereditarietà, consulta Python Inheritance. Per pattern OOP più avanzati, consulta Python Abstract Base Classes.

Cos'è una Classe?

Pensa a una classe come a una formina per biscotti e a un object come al biscotto. Definisci la forma una volta sola (la classe), poi stampi quanti biscotti (oggetti) ti servono. Ogni object condivide la stessa struttura ma conserva i propri dati.

class Dog:
    pass  # an empty class — valid but not very useful yet

La parola chiave class seguita da un nome e dai due punti crea una nuova classe. Per convenzione, i nomi delle classi usano il formato CapWords (detto anche PascalCase): MyClass, BankAccount, HttpRequest.

Il Metodo __init__

Il metodo __init__ (abbreviazione di initialise) viene eseguito automaticamente ogni volta che crei un nuovo object. Imposta lo stato iniziale dell'object assegnando valori ai suoi attributi di istanza.

class Dog:
    def __init__(self, name, age):
        self.name = name   # instance attribute
        self.age = age     # instance attribute

Il primo parametro è sempre self — fa riferimento all'object che viene creato. Python lo passa automaticamente; non devi mai fornirlo tu stesso.

Attributi di Istanza vs. Attributi di Classe

TipoDefinito dentroAppartiene aCondiviso?
Attributo di istanza__init__ (tramite self)Ogni objectNo — ogni object ha la propria copia
Attributo di classeCorpo della classe (fuori da qualsiasi metodo)La classe stessaSì — tutti gli oggetti condividono un'unica copia
class Dog:
    species = "Canis familiaris"  # class attribute — shared by all Dogs

    def __init__(self, name, age):
        self.name = name   # instance attribute
        self.age = age     # instance attribute

fido = Dog("Fido", 3)
bella = Dog("Bella", 5)

print(fido.species)    # Canis familiaris
print(bella.species)   # Canis familiaris  (same class attribute)
print(fido.name)       # Fido
print(bella.name)      # Bella             (different instance attributes)

Usa un attributo di classe quando un valore è lo stesso per ogni object di quel tipo (ad es. la specie di tutti i cani). Usa gli attributi di istanza per i dati che variano per ogni object.

Definire i Metodi

Un metodo è una funzione definita all'interno di una classe. Come __init__, riceve sempre self come primo parametro in modo da poter accedere agli attributi dell'object.

class Dog:
    species = "Canis familiaris"

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def bark(self):
        return f"{self.name} says: Woof!"

    def description(self):
        return f"{self.name} is {self.age} years old."

Un metodo si chiama su un object usando la notazione punto — Python passa automaticamente l'object come self:

fido = Dog("Fido", 3)
print(fido.bark())          # Fido says: Woof!
print(fido.description())   # Fido is 3 years old.

Il Metodo __str__

Python chiama __str__ quando passi un object a print() o a str(). Senza di esso, ottieni un indirizzo poco utile come <__main__.Dog object at 0x...>. Definirlo rende il debug molto più semplice.

class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f"Dog(name={self.name!r}, age={self.age})"

fido = Dog("Fido", 3)
print(fido)   # Dog(name='Fido', age=3)

Creare e Utilizzare Oggetti

Creare un object si chiama istanziazione. Si chiama la classe come una funzione, passando gli argomenti che __init__ si aspetta (escluso self):

python— editable, runs on the server

Puoi creare quanti oggetti vuoi dalla stessa classe — ognuno è indipendente:

class Rectangle:
    def __init__(self, width, height=1):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

    def perimeter(self):
        return 2 * (self.width + self.height)

r1 = Rectangle(4, 3)
r2 = Rectangle(5)      # height defaults to 1

print(r1.area())        # 12
print(r1.perimeter())   # 14
print(r2.area())        # 5

Nota che height=1 fornisce un valore predefinito: se ometti il secondo argomento, Python usa automaticamente 1.

Modificare ed Eliminare Attributi

Puoi modificare o aggiungere attributi a un object dopo che è stato creato, ed eliminarli con del:

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

p = Person("Alice", 30)
print(p.age)      # 30

p.age = 31        # modify an existing attribute
print(p.age)      # 31

p.email = "[email protected]"   # add a new attribute at runtime
print(p.email)    # [email protected]

del p.email       # delete the attribute
# print(p.email)  # would raise AttributeError

Sebbene Python consenta di aggiungere attributi liberamente, è più pulito dichiarare tutti gli attributi all'interno di __init__ in modo che la struttura della classe sia evidente a colpo d'occhio.

Verificare i Tipi degli Oggetti

Usa isinstance() per verificare se un object è un'istanza di una particolare classe. Restituisce True per la classe stessa e per tutte le sue classi padre:

class Animal:
    pass

class Dog(Animal):
    pass

rex = Dog()
print(isinstance(rex, Dog))     # True
print(isinstance(rex, Animal))  # True  — Dog is a subclass of Animal
print(type(rex) is Dog)         # True
print(type(rex) is Animal)      # False — type() does not climb the hierarchy

Preferisci isinstance() rispetto a type() is nella maggior parte del codice, perché gestisce correttamente le sottoclassi.

Una Prima Panoramica sull'Ereditarietà

L'ereditarietà consente a una nuova classe di riutilizzare ed estendere il comportamento di una classe esistente. La nuova classe (figlia o sottoclasse) ottiene automaticamente tutti gli attributi e i metodi della classe padre:

class Animal:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return f"{self.name} makes a sound."

class Dog(Animal):
    def speak(self):                     # override the parent method
        return f"{self.name} says: Woof!"

class Cat(Animal):
    def speak(self):
        return f"{self.name} says: Meow!"

dog = Dog("Rex")
cat = Cat("Whiskers")
print(dog.speak())             # Rex says: Woof!
print(cat.speak())             # Whiskers says: Meow!
print(isinstance(dog, Animal)) # True

Sia Dog che Cat ereditano __init__ da Animal, quindi non hanno bisogno di ridefinirlo. Sovrascrivono solo speak() per fornire un comportamento specifico alla razza.

Per un trattamento completo dell'ereditarietà — inclusi super(), l'ereditarietà multipla e l'ordine di risoluzione dei metodi — consulta Python Inheritance.

Quando Usare una Classe?

Le classi hanno più senso quando:

  • Hai dati e comportamenti che stanno insieme (un conto bancario che sa come depositare e prelevare).
  • Hai bisogno di più oggetti indipendenti dello stesso tipo (molti oggetti Dog, ognuno con nome ed età diversi).
  • Vuoi modellare entità del mondo reale con un'identità chiara.

Le semplici funzioni di utilità che si limitano a trasformare l'input in output spesso funzionano meglio come funzioni semplici. Python non richiede che tutto sia in una classe.

ConcettoCosa fa
classDefinisce un nuovo tipo
__init__Inizializza gli attributi di istanza quando viene creato un object
selfFa riferimento all'object corrente all'interno di un metodo
Attributo di istanzaDato appartenente a un singolo object specifico
Attributo di classeDato condiviso tra tutti gli oggetti della classe
MetodoUna funzione definita all'interno di una classe; riceve sempre self
__str__Controlla come print() visualizza l'object
isinstance()Verifica se un object è un'istanza di una classe o delle sue sottoclassi
EreditarietàConsente a una classe figlia di riutilizzare ed estendere una classe padre

Esercitazione

Pratica
What is the correct way to create a class in Python?
What is the correct way to create a class in Python?
Was this page helpful?