Section Overview
It’s not enough to write code that works — you need to write code that can be understood, fixed, and improved over time. This section introduces the techniques and habits that help you write clean, reliable, and maintainable Python code.
By the end of this section, you will be able to:
- Use debugging techniques to find and fix errors
- Understand and use logging to monitor programs
- Follow established Python coding conventions
- Write code that others (and future you) can easily understand
Lesson 1: Debugging Basics
Syntax errors and runtime errors are part of programming. Here are some ways to track them down:
- Add temporary
print()
statements to trace variable values - Use Python's built-in error messages and traceback info
- Check indentation, missing colons, and wrong variable names
Example:
def divide(a, b):
print("Dividing:", a, b)
return a / b
print(divide(10, 0)) # Will raise ZeroDivisionError
Lesson 2: Using assert
to Catch Bugs Early
An assert
is a quick check you can insert to catch logic errors during development:
def calculate_discount(price, discount):
assert discount < 1.0, "Discount must be less than 1"
return price * (1 - discount)
Assertions stop the program if a condition is false. They're not used in production code, but they’re helpful while building and testing.
Lesson 3: Introduction to Logging
Logging gives you better control and insight than print()
— especially in larger applications.
import logging
logging.basicConfig(level=logging.INFO)
logging.info("Starting program")
Log levels (from lowest to highest severity):
DEBUG
INFO
WARNING
ERROR
CRITICAL
Example:
import logging
logging.basicConfig(level=logging.DEBUG)
def divide(x, y):
logging.debug(f"Trying to divide {x} by {y}")
try:
result = x / y
except ZeroDivisionError:
logging.error("Cannot divide by zero")
return None
return result
Lesson 4: Writing Clean Code (Best Practices)
Follow Python’s official style guide: PEP 8
Key habits:
- Use meaningful variable names (
total_price
instead of tp
) - Keep functions short and focused
- Use comments to explain why, not what
- Follow consistent indentation (4 spaces per level)
- Group related functions in modules
Bad:
def d(x, y): return x/y
Better:
def divide(x, y):
"""Returns the result of x divided by y."""
return x / y
Lesson 5: Handling Errors Gracefully with Try/Except
Don't let a single error crash your whole program. Use try/except blocks:
try:
age = int(input("Enter your age: "))
print(f"In 10 years you will be {age + 10}")
except ValueError:
print("Please enter a valid number.")
You can also use finally
to run cleanup code:
try:
f = open("file.txt")
# work with file finally:
f.close()
Quiz: Check Your Understanding
1. What's the difference between print()
and logging?
Answer: Logging provides different levels of detail and can be turned on/off or saved to files.
2. When should you use assert
?
Answer: During development to catch programming errors early.
3. What does PEP 8
refer to?
Answer: The official Python style guide.
4. What log level would you use to record an unexpected error?
Answer: ERROR
Practice Exercise: Write Clean, Logged Code
Write a function safe_divide(x, y)
that:
- Logs each attempt to divide
- Catches and logs division-by-zero errors
- Returns
None
if the division fails
Add an assert
to check that both arguments are numbers.