Programmazione orientata agli oggetti in Python
La OOP organizza un programma attorno a oggetti che possiedono stato ed espongono comportamenti tramite interfacce chiare.
Cos’è la programmazione orientata agli oggetti in Python?
La OOP modella un sistema come oggetti che collaborano. Ogni oggetto unisce stato e operazioni consentite, chiarendo le responsabilità nelle applicazioni grandi.
I quattro principi fondamentali
- Incapsulamento: riunire stato e comportamento e controllarne l’accesso.
- Astrazione: mostrare un’interfaccia utile nascondendo i dettagli superflui.
- Ereditarietà: specializzare una classe solo per una vera relazione is-a.
- Polimorfismo: usare la stessa operazione con oggetti diversi e comportamento appropriato.
Progettazione dell’esempio
- BankAccount possiede il saldo e valida i depositi.
- SavingsAccount riutilizza il contratto di base.
- SavingsAccount ridefinisce month_end per applicare gli interessi.
- Il ciclo usa tutti i conti tramite la stessa interfaccia.
Esempio di base
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner
self._balance = float(balance)
@property
def balance(self):
return self._balance
def deposit(self, amount):
if amount <= 0:
raise ValueError("Deposit must be positive")
self._balance += amount
def month_end(self):
return "No interest"
class SavingsAccount(BankAccount):
def __init__(self, owner, balance, interest_rate):
super().__init__(owner, balance)
self.interest_rate = interest_rate
def month_end(self):
self._balance *= 1 + self.interest_rate
return "Interest applied"
accounts = [
BankAccount("Ada", 100),
SavingsAccount("Lin", 200, 0.05),
]
accounts[0].deposit(50)
for account in accounts:
status = account.month_end()
print(f"{account.owner}: {account.balance:.2f} ({status})")
Output previsto
Ada: 150.00 (No interest)
Lin: 210.00 (Interest applied)
I quattro principi OOP in pratica
Questi esempi mirati mostrano come Python applica incapsulamento, astrazione, ereditarietà e polimorfismo nel codice quotidiano.
Incapsulamento
riunire stato e comportamento e controllarne l’accesso.
class BankAccount:
def __init__(self, balance=0):
# Double underscores prevent accidental direct access.
self.__balance = balance
@property
def balance(self):
# Expose read access without exposing mutation.
return self.__balance
def deposit(self, amount):
# Keep validation next to the state it protects.
if amount <= 0:
raise ValueError("Amount must be positive")
self.__balance += amount
account = BankAccount(100)
account.deposit(50)
print(account.balance) # 150
Astrazione
mostrare un’interfaccia utile nascondendo i dettagli superflui.
from abc import ABC, abstractmethod
class PaymentMethod(ABC):
@abstractmethod
def pay(self, amount):
# Callers know what pay does, not how each provider does it.
pass
class CreditCard(PaymentMethod):
def pay(self, amount):
# The concrete class hides its payment implementation.
return f"Paid ${amount:.2f} by card"
payment = CreditCard()
print(payment.pay(25))
Ereditarietà
specializzare una classe solo per una vera relazione is-a.
class Employee:
def __init__(self, name):
self.name = name
def describe(self):
return self.name
class Developer(Employee):
def __init__(self, name, language):
# Reuse initialization from the parent class.
super().__init__(name)
self.language = language
def describe(self):
# Extend inherited behavior instead of duplicating it.
return f"{super().describe()} writes {self.language}"
print(Developer("Ada", "Python").describe())
Polimorfismo
usare la stessa operazione con oggetti diversi e comportamento appropriato.
class EmailNotification:
def send(self, message):
return f"Email: {message}"
class SmsNotification:
def send(self, message):
return f"SMS: {message}"
def notify(channels, message):
for channel in channels:
# The same call selects behavior from each concrete object.
print(channel.send(message))
channels = [EmailNotification(), SmsNotification()]
notify(channels, "Order shipped")
Come funziona
BankAccount incapsula il saldo. SavingsAccount eredita l’interfaccia e ridefinisce month_end. Il ciclo usa entrambi gli oggetti allo stesso modo e Python seleziona il metodo a runtime.
Modifica i valori ed esegui il programma nel compilatore Python online CodeUtility senza installare Python.
Esercizi pratici
Modifica gli input e verifica i casi limite prima di usare dataset più grandi.
- Prevedi l’output prima dell’esecuzione.
- Gestisci input vuoti o non validi.
- Sposta la logica in una funzione e aggiungi test.