Making Python Code More Reliable¶

Reliable code comes from checking, observing, and fixing¶
Once code is spread across functions, modules, and packages, trust matters as much as structure. Testing checks expected behavior, debugging finds the cause of wrong behavior, and logging leaves a trail you can inspect when systems become harder to reason about.
Why this matters¶
A project can be well organized and still be unreliable. Reliability practices matter because they help you:
catch mistakes before users or teammates do
understand why a function behaved differently than expected
trace what happened in a longer workflow or pipeline
make growing codebases safer to change over time
Continuity from the modules notebook
Modules and packages organize the system. Testing and debugging help you trust that the organized system still works.
Core Explanation¶
Testing asks, Does this code produce the expected result? Debugging asks, Why did this code fail or behave unexpectedly? Logging asks, What happened while the program was running?
These are related but different habits. Testing checks outcomes. Debugging diagnoses causes. Logging records signals that help you understand behavior over time.
Three practical reliability moves¶
Write small checks that compare actual results with expected results.
Narrow the problem down until you can explain what is wrong and where it begins.
Record useful events, values, or states so behavior can be traced without manually stepping through everything.
def safe_divide(a, b):
if b == 0:
return "Cannot divide by zero"
return a / b
print(safe_divide(10, 2))
print(safe_divide(10, 0))5.0
Cannot divide by zero
Worked Example: test the normal case and the edge case¶
A function becomes easier to trust when you check more than one kind of input.
Example mindset
Instead of assuming a function works, try a normal case, an edge case, and an invalid case when possible. That habit catches many mistakes early.
Logging idea¶
Even a simple print statement can act like a beginner-friendly log when you are tracing a workflow.
def process_order(order_id):
print(f"Starting order {order_id}")
print("Checking inventory")
print("Finishing order")Guided Check¶
What is the main goal of debugging?¶
Exercises¶
Exercise 1: Write a simple test¶
Create a short check for a function that adds two values and prints whether the result matches what you expected.
Hint
Pick one input pair such as 2 and 3, compute the function result, and compare it to 5.
Exercise 2: Describe a debugging plan¶
A program gives the wrong output but does not crash. Describe the first three things you would inspect before changing code.
Hint
Think in order: expected output, actual output, and the smallest part of the program where they begin to differ.
Exercise 3: Explain logging¶
Give one example of something you would log in a business workflow such as order processing, scoring, or reporting.
Hint
Useful logs often mention what step started, what key value changed, or why a branch was taken.
Quick Summary
testing checks expected behavior
debugging identifies the cause of failures
logging helps trace what happened during execution
reliability practices save time as projects and teams grow
The next notebook is a short self-check covering the chapter.
def is_even(value):
return value % 2 == 0
print(is_even(4))
print(is_even(5))True
False
Practice Lab¶
Expected output
True
FalseExpected output
5.0
Cannot divide by zeroExtension idea
Add a third check that confirms safe_divide(9, 3) returns 3.0, or add a print-based log that shows which branch the function took.
Guided Practice¶
Why are tests useful?¶
What should `safe_divide(10, 0)` return in the example above?¶
Key Takeaway¶
Reliable code is rarely produced by luck. It comes from checking assumptions, observing behavior, and improving the program deliberately.