Chapter 18: Bugs — Solutions
Worked solutions to the 20 Find the Bug exercises in Chapter 18: Bugs. Each one names the kind of bug, explains why the original misbehaved, and shows the corrected program.
Solutions stay folded until you open them — try the exercise first; the diagnosis is where the learning is.
Solutions 18.1.1–18.1.5
Solution 18.1.1 — Rectangle perimeter
Show the diagnosis and the fix
Bug type: Syntax
The def header is missing the colon that must end every function definition line, so Python cannot parse the file. Adding the colon lets the function be defined and called.
def perimeter(length, width):
return 2 * (length + width)
print(perimeter(8, 5)) # 26
Solution 18.1.2 — Tip calculator
Show the diagnosis and the fix
Bug type: Syntax
The opening parenthesis after bill * is never closed, leaving an unbalanced bracket that the parser rejects. Closing the parenthesis fixes the expression.
bill = 40.0
tip_rate = 0.15
total = bill + (bill * tip_rate)
print(total) # 46.0
Solution 18.1.3 — Passing grade
Show the diagnosis and the fix
Bug type: Syntax
The condition uses = (assignment) where a comparison == is required, which is a syntax error inside an if. Using >= expresses the intended “score is at least 60” test.
score = 72
if score >= 60:
print("Pass")
else:
print("Fail")
Solution 18.1.4 — Weekly distance
Show the diagnosis and the fix
Bug type: Syntax
There is a missing operator (or comma) between tuesday and wednesday; two names sitting side by side cannot be parsed. Adding the + sums all three days.
monday = 3.2
tuesday = 4.1
wednesday = 2.7
total = monday + tuesday + wednesday
print(total) # 10.0
Solution 18.1.5 — Counting change
Show the diagnosis and the fix
Bug type: Syntax
The print line is not indented under the for, so Python raises an IndentationError because a loop body is expected. Indenting the line by four spaces puts it inside the loop.
coins = [25, 10, 5, 1]
for coin in coins:
print(coin)
Solutions 18.2.1–18.2.5
Solution 18.2.1 — Average speed
Show the diagnosis and the fix
Bug type: Runtime
Calling the function with hours = 0 divides by zero at run time, raising ZeroDivisionError. Guarding against a zero time (or passing a real duration) avoids the crash.
def average_speed(distance, hours):
if hours == 0:
return "Time cannot be zero"
return distance / hours
print(average_speed(120, 2)) # 60.0
Solution 18.2.2 — Final price with tax
Show the diagnosis and the fix
Bug type: Runtime
The expression references tax, but the variable defined above is tax_rate, so Python raises a NameError. Using the correct name computes the taxed price.
price = 50.0
tax_rate = 0.08
final_price = price + (price * tax_rate)
print(final_price) # 54.0
Solution 18.2.3 — Doubling a recipe
Show the diagnosis and the fix
Bug type: Runtime
cups_of_flour is a string, and multiplying a string by a float raises TypeError. Storing the quantity as a number lets the multiplication work.
cups_of_flour = 2.0
doubled = cups_of_flour * 2.0
print(doubled) # 4.0
Solution 18.2.4 — Last student’s score
Show the diagnosis and the fix
Bug type: Runtime
len(scores) is 4, but valid indices run 0 to 3, so scores[4] raises IndexError. The last element is at index len(scores) - 1 (or simply -1).
scores = [88, 91, 79, 95]
last_index = len(scores) - 1
print(scores[last_index]) # 95
Solution 18.2.5 — Looking up a planet
Show the diagnosis and the fix
Bug type: Runtime
The key "mars" is lowercase, but the dictionary key is "Mars"; dictionary lookups are case sensitive, so this raises KeyError. Matching the stored key returns the value.
moons = {"Earth": 1, "Mars": 2, "Venus": 0}
print(moons["Mars"]) # 2
Solutions 18.3.1–18.3.5
Solution 18.3.1 — Rectangle area
Show the diagnosis and the fix
Bug type: Logical
The program runs but uses + where area requires multiplication, so it returns 10 instead of 24. Multiplying length by width gives the correct area.
def area(length, width):
return length * width
print(area(6, 4)) # 24
Solution 18.3.2 — Average of three grades
Show the diagnosis and the fix
Bug type: Logical
Operator precedence divides only c by 3 before adding, so the result is wrong. Parenthesizing the sum before dividing computes the true average.
def average(a, b, c):
return (a + b + c) / 3
print(average(80, 90, 100)) # 90.0
Solution 18.3.3 — Counting to ten
Show the diagnosis and the fix
Bug type: Logical
range(1, 10) stops at 9 because the upper bound is excluded, so 10 is never printed (an off-by-one error). Using range(1, 11) includes 10.
for number in range(1, 11):
print(number)
Solution 18.3.4 — Discounted price
Show the diagnosis and the fix
Bug type: Logical
Multiplying by the discount rate gives the amount taken off, not the price paid, so the result is 20 instead of 60. The customer pays the remaining fraction, 1 - discount_rate.
price = 80.0
discount_rate = 0.25
final_price = price * (1 - discount_rate)
print(final_price) # 60.0
Solution 18.3.5 — Fahrenheit to Celsius
Show the diagnosis and the fix
Bug type: Logical
The conversion factor is inverted: Fahrenheit to Celsius multiplies by 5 / 9, not 9 / 5. Swapping the fraction gives the right temperature.
def f_to_c(f):
return (f - 32) * 5 / 9
print(f_to_c(212)) # 100.0
Solutions 18.4.1–18.4.5
Solution 18.4.1 — Total grocery cost
Show the diagnosis and the fix
Bug type: Logical
Printing the subtotal reveals it is too low: the milk price is subtracted instead of added. Changing the - to + totals all three items.
def total_cost(apples, bread, milk):
subtotal = apples + bread + milk
return subtotal
print(total_cost(3.50, 2.25, 1.75)) # 7.5
Solution 18.4.2 — Circle circumference
Show the diagnosis and the fix
Bug type: Logical
Printing the returned value shows it is half the expected size: the formula omits the factor of 2 (circumference is 2 * pi * radius). Adding the 2 corrects it.
def circumference(radius):
pi = 3.14159
return 2 * pi * radius
print(circumference(5)) # about 31.4
Solution 18.4.3 — Sum of a list
Show the diagnosis and the fix
Bug type: Logical
Printing total inside the loop shows it only ever holds the latest value: the line replaces the running sum instead of adding to it. Using += accumulates the total.
rainfall = [1.2, 0.8, 2.0, 1.5]
total = 0
for amount in rainfall:
total += amount
print(total) # 5.5
Solution 18.4.4 — Sale price
Show the diagnosis and the fix
Bug type: Logical
Printing sale_price shows it equals the discount amount, not the discounted price, so the subtraction yields the wrong savings. The savings are simply price * discount_rate.
def savings(price, discount_rate):
return price * discount_rate
print(savings(120, 0.30)) # 36.0
Solution 18.4.5 — Speed from distance and time
Show the diagnosis and the fix
Bug type: Logical
Printing result reveals the division is inverted: speed is distance divided by time, not time divided by distance. Swapping the operands gives the correct speed.
def speed(distance_km, time_hours):
result = distance_km / time_hours
return result
print(speed(150, 3)) # 50.0