Lesson 27 of 35Python
Python · Lesson 27 · 35 minutes
Bug detective 2: classes and exceptions
What you'll learn
- Read longer error messages (tracebacks) step by step
- Find bugs in classes (forgotten
self, wrong calculation) - Check things deliberately with
assertandf"{x=}"
Reading long error messages
The bigger a program, the longer the error messages get. Python then shows a traceback: the chain of function calls that led to the error. The most important part is still the last line:
class Animal:
def __init__(self, name):
self.name = name
def introduce(self):
return "I am " + self.nmae
dog = Animal("Rex")
print(dog.introduce())AttributeError: 'Animal' object has no attribute 'nmae' – a typo in the attribute name. Codelix even suggests the right name.
The classic: forgetting self
class Counter:
def __init__(self):
count = 0 # ← without self. this is just a local variable
def plus(self):
self.count += 1
c = Counter()
c.plus()In a method, everything the object should remember belongs on self. Otherwise it’s gone once the method ends.
Tool: assert and f”{x=}”
With assert you check an assumption. If it’s wrong, Python stops straight away – exactly where things first go wrong:
def net(gross):
return gross / 1.2
price = net(120)
print(f"{price=}") # shows the name AND the value
assert round(price) == 100, "Net price is wrong"
print("All correct!")f"{price=}" is a debugging trick: Python writes the name along with the value.
Detective rule 2: explain your code out loud – to a friend, a cuddly toy or a rubber duck. While explaining, you’ll surprisingly often spot the bug yourself. Professionals call this rubber duck debugging.
Your task
Your turn
The class Account has three bugs. It should work like this: a new account starts with a balance of 0. deposit(amount) increases the balance – negative amounts should raise a ValueError. withdraw(amount) reduces the balance and raises a ValueError if there isn't enough money.
class Account:
def __init__(self, owner):
self.owner = owner
balance = 0
def deposit(self, amount):
if amount < 0:
print("Only positive amounts!")
self.balance += amount
def withdraw(self, amount):
if amount > self.balance:
raise ValueError("Not enough money")
self.balance + amount
account = Account("Ana")
account.deposit(50)
account.withdraw(20)
print(account.owner, "has", account.balance, "pounds")- Something to think about
Something is missing before balance in
__init__– withoutself. it's just a variable that disappears straight away. - Which command helps?
Look at the last line of withdraw. Is the result stored anywhere?
A message with
print()doesn't stop the program. UseraiseValueError(...)like in withdraw. - Gap code – fill in the ___
class Account: def __init__(self, owner): self.owner = owner self.balance = ___ def deposit(self, amount): if amount < 0: ___ self.balance += amount def withdraw(self, amount): if amount > self.balance: raise ValueError("Not enough money") self.balance -= ___ account = Account("Ana") account.deposit(50) account.withdraw(20) print(account.owner, "has", account.balance, "pounds")
Solve it without hints to earn a ⭐ on your progress page.
Show solution🔒 Unlocks after all hints or 2 checks
Try it yourself first – mistakes teach you the most. Here is one possible solution:
class Account:
def __init__(self, owner):
self.owner = owner
self.balance = 0
def deposit(self, amount):
if amount < 0:
raise ValueError("Only positive amounts!")
self.balance += amount
def withdraw(self, amount):
if amount > self.balance:
raise ValueError("Not enough money")
self.balance -= amount
account = Account("Ana")
account.deposit(50)
account.withdraw(20)
print(account.owner, "has", account.balance, "pounds")