Object-Oriented Python
Classes and objects
A class bundles data and the behaviour that works on it.
class BankAccount:
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
def __repr__(self):
return f"BankAccount({self.owner!r}, {self.balance})"
acct = BankAccount("Ada")
acct.deposit(50)
print(acct) # BankAccount('Ada', 50)
self is the object the method was called on. __init__ sets up a new object.
Properties: computed or protected attributes
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
Class and static methods
class User:
def __init__(self, email): self.email = email
@classmethod
def from_dict(cls, data):
return cls(data["email"])
@staticmethod
def is_valid_email(text):
return "@" in text
Inheritance
class SavingsAccount(BankAccount):
def __init__(self, owner, balance=0, rate=0.02):
super().__init__(owner, balance)
self.rate = rate
def add_interest(self):
self.deposit(self.balance * self.rate)
Prefer composition (an object holding other objects) over deep inheritance trees. Two levels is usually plenty.
Dataclasses: less boilerplate
from dataclasses import dataclass, field
@dataclass
class OrderItem:
sku: str
qty: int
price: float
@property
def total(self):
return self.qty * self.price
@dataclass
class Order:
id: int
items: list[OrderItem] = field(default_factory=list)
def total(self):
return sum(i.total for i in self.items)
Dataclasses generate __init__, __repr__ and __eq__ for you. Use @dataclass(frozen=True) for immutable values.
Special methods
__len__, __iter__, __eq__, __lt__, __str__ let your objects work with len(), for, ==, sorted() and print().
When to use classes
Use a class when data and behaviour belong together and you have several instances (accounts, orders, users), or when a framework expects them (SQLAlchemy models, Flask-WTF forms). For a one-off calculation, a function is simpler.
Exercise
Model a shopping cart: Product (validated price), CartItem and Cart with add, remove, total and apply_coupon(code). Use dataclasses where they fit.
Check yourself
- What is
self? - When is a
@classmethoduseful? - Why prefer composition over deep inheritance?
I tuoi progressi sono salvati solo in questo browser.
Invia per la revisione (10 punti)