io-and-debugging
I/O and Debugging — robust interaction and finding bugs
Safe I/O patterns, parsing, and practical debugging workflows.
Console input and output
Use input() for simple interactive programs and format output with f-strings for clarity.
name = input("Enter your name: ")
print(f"Hello, {name}")
For scripts intended to be used non-interactively, prefer command-line arguments (e.g., argparse) so the program can be automated.
File I/O (text and CSV)
Use context managers to ensure files are closed correctly.
with open("data.txt", "r", encoding="utf-8") as f:
text = f.read()
with open("out.txt", "w", encoding="utf-8") as f:
f.write(text.upper())
Parsing CSV (simple):
import csv
with open("students.csv", newline='', encoding='utf-8') as csvfile:
reader = csv.reader(csvfile)
for row in reader:
name, score = row[0], float(row[1])
Robust parsing patterns
- Validate input and use
try/exceptto report meaningful errors (don't catch Exception blindly). - Use
strip()to remove extra whitespace before conversion.
Logging vs print
- Use
logginginstead ofprintfor anything but the simplest scripts; logging levels (DEBUG, INFO, WARNING, ERROR) let you control verbosity.
import logging
logging.basicConfig(level=logging.INFO)
logging.debug("This is a debug message")
logging.info("Started processing")
Debugging workflow
- Read the error message and the stack trace — it often points directly to the cause.
- Reproduce the bug with the smallest possible input.
- Insert assertions or temporary prints to inspect values.
- Use an interactive debugger (e.g.,
pdbor your IDE's debugger) to step through and inspect variables. - Once fixed, add a unit test that reproduces the bug to prevent regressions.
Example using pdb:
import pdb
def buggy(v):
pdb.set_trace()
return v + 1
buggy('x')
Common errors and how to fix them
- SyntaxError: check the line and preceding lines for missing
:, unmatched parentheses or indent problems. - NameError: a variable is used before it has been assigned — check scope and spelling.
- ValueError/TypeError: ensure you are passing values of the correct type; validate and coerce if necessary.
Testing and quick checks
- Use
assertfor small checks during development:assert x >= 0, "x must be non-negative". - For structured tests use
pytestorunittestand keep tests in atests/folder.
Example: reading numbers until blank and reporting sum (robust)
def read_numbers_and_sum():
total = 0
while True:
s = input("Enter a number (blank to finish): ")
if not s.strip():
break
try:
total += int(s)
except ValueError:
print("Invalid number, try again")
return total
if __name__ == '__main__':
print('Total:', read_numbers_and_sum())
See functions.md for exhibiting I/O in small testable functions and exercises.md for practice problems that require file and console I/O.