Lesson 11 of 11
Time to build a small banking system that uses everything from this module: a base class, two subclasses, protected state, validation, and dunder methods.
The base account
BankAccount protects its balance and routes every change through validated methods — the
encapsulation from lesson 5.8.
class BankAccount:
"""A basic bank account with a protected balance."""
account_count = 0
def __init__(self, owner, balance=0):
self.owner = owner
self._balance = balance
self._transactions = []
BankAccount.account_count += 1
@property
def balance(self):
return self._balance
def deposit(self, amount):
if amount <= 0:
return "Deposit must be positive"
self._balance += amount
self._transactions.append(("deposit", amount))
return "OK"
def withdraw(self, amount):
if amount <= 0:
return "Amount must be positive"
if amount > self._balance:
return "Insufficient funds"
self._balance -= amount
self._transactions.append(("withdraw", amount))
return "OK"
def __str__(self):
return f"{self.owner}: ${self._balance:.2f}"
def __repr__(self):
return f"BankAccount({self.owner!r}, {self._balance})"
def __len__(self):
return len(self._transactions)
acct = BankAccount("Ada", 100)
acct.deposit(50)
acct.withdraw(30)
print(acct)
print(len(acct))
Note account_count is a class attribute updated with BankAccount.account_count += 1 —
the lesson 5.4 rule. __len__ returns the transaction count, which is a natural meaning of
"how big is this account's history."
Two subclasses
Both extend __init__ with super() and override withdraw() with their own rules.
class SavingsAccount(BankAccount):
"""Earns interest, but no overdraft."""
def __init__(self, owner, balance=0, rate=0.02):
super().__init__(owner, balance)
self.rate = rate
def add_interest(self):
interest = self._balance * self.rate
self._balance += interest
self._transactions.append(("interest", interest))
return interest
def __str__(self):
return f"{super().__str__()} (savings)"
class CheckingAccount(BankAccount):
"""Allows going overdrawn up to a limit."""
def __init__(self, owner, balance=0, overdraft=100):
super().__init__(owner, balance)
self.overdraft = overdraft
def withdraw(self, amount):
if amount <= 0:
return "Amount must be positive"
if amount > self._balance + self.overdraft:
return "Exceeds overdraft limit"
self._balance -= amount
self._transactions.append(("withdraw", amount))
return "OK"
def __str__(self):
return f"{super().__str__()} (checking)"
CheckingAccount.withdraw() fully replaces the parent's rule, because the logic genuinely
differs. __str__ in both extends the parent with super().__str__() rather than repeating
the formatting.
Polymorphism in action
The reporting code doesn't care what kind of account it has:
accounts = [
SavingsAccount("Ada", 1000),
CheckingAccount("Grace", 500),
BankAccount("Alan", 250),
]
for account in accounts:
print(account)
total = sum([a.balance for a in accounts])
print(f"Total: ${total:.2f}")
Adding a new account type means writing a new class — this loop never changes. That's lesson 5.9.
Try it yourself
Take it further
- Add a
transfer(self, other, amount)method that withdraws from one account and deposits into another — and refuses if the withdrawal fails. - Give
BankAccountahistory()method that returns a readable list of transactions. - Add
__eq__so two accounts are equal when they have the same owner and balance. - Add a
Transactionclass instead of tuples, with its own__repr__.
One real limitation: close the program and every account vanishes. Module 6 covers saving objects to a file so your data survives.
Module 5 complete
You can now design your own types: classes with constructors and methods, class versus instance
data, inheritance with super(), encapsulated state, polymorphic behaviour, and dunder methods
that make your objects feel native.
That's the toolkit for structuring a real codebase — instead of a pile of loose functions and dictionaries, you can model the actual things your program is about.
Next up: Module 6 — File Handling & Error Management, where your data finally starts surviving past the end of the program.
Questions about this lesson
Log in to ask a question.