Concepts / Debugging with Print Statements and Tracebacks

Debugging with Print Statements and Tracebacks

Try/except structures prevent program crashes by catching exceptions and executing recovery code when operations fail.

  • Programming

A File Name Is an Assumption

When a program opens a file, it assumes that the file exists and can be read. That assumption may be wrong: a user may enter a filename that does not exist, or the file may be locked by another program. Without error handling, the program can crash and display a traceback that confuses the user. A try/except structure lets the program anticipate the failure, provide useful feedback, and stop cleanly when the file cannot be opened.

Treat the open() operation as a potential failure point rather than assuming it will always succeed.

Two Paths Through try and except

succeedsraisescontinuesjumps tocallsopen()inside tryFile objectfhand assignedfor loopcount subject linesFileNotFoundErroropening failsexcept blockrecovery codeexit()clean termination
What happens next when the file-opening operation succeeds versus when it raises an exception?

The try block contains the operation that may fail. If open() succeeds, the file object is assigned to fhand, the except block is skipped, and the program continues to the for loop that counts lines beginning with Subject. If open() raises a FileNotFoundError, Python stops executing the try block immediately and moves to the except block. The later for loop and result print do not execute.

What do you think happens?

A user enters a filename that does not exist. Which part runs next?

  • The for loop that counts subject lines
  • The except block
  • The final result print
Reveal answer

Answer: The except block

The open() call raises a FileNotFoundError. Python immediately stops the try block and jumps to the except block, so the later loop and result print never execute.

Recovery Code That Protects the Rest

The except block is not only a place to report a problem. It is the recovery path for the failed operation. In this file example, recovery has two parts: print a message that identifies the file the user tried to open, then call exit() because opening the file was a critical operation. Exiting prevents the program from attempting to use an unopened file.

python

Tracing a Missing File

The user enters missing.txt, and that file does not exist.

1. Read the filename: The program receives missing.txt as the filename to open.

2. Attempt open(): The open() operation fails and raises FileNotFoundError.

3. Enter except: Python stops the try block and transfers control to the except block.

4. Give feedback: The program prints a message identifying missing.txt as the file that cannot be opened.

5. Stop safely: exit() terminates the program, so the for loop and final count do not run.

The user receives a meaningful file-opening message instead of the program continuing without an opened file.

Raw Tracebacks and Helpful Messages

replace withRaw tracebacktechnical detailsFile cannot be openedmissing.txt
How does the technical error produced by the system differ from the message shown to the user?

Without error handling, Python displays a raw traceback. The source describes this as a technical message full of internal details that can confuse most users. With try/except, the program controls what the user sees. A message such as File cannot be opened: missing.txt identifies both the problem and the filename involved.

Print statements can also support tracing while you study the control flow: place a visible message before the operation and another message in the recovery path. The important question is what the output tells you about the path taken. If the opening fails, execution reaches the except message and then exits; it does not reach the later file-processing statements.

Mistakes That Break Recovery

  • Putting open() outside the try block

    The file-opening operation is the point that can fail, so a failure happens before the try block can handle it.

    Fix: Wrap the open() operation itself in the try block.

  • Continuing after a critical opening failure

    The program may attempt to use a file that was never opened.

    Fix: Call exit() in the except block when opening the file is required for the rest of the program.

  • Showing only the raw traceback to the user

    The traceback contains technical details that can confuse the user.

    Fix: Catch the failure and print a user-friendly message that identifies the file.

  • Giving feedback without identifying the filename

    The user is not told which attempted file caused the problem.

    Fix: Include the filename in the recovery message, such as File cannot be opened: missing.txt.

Practice the Two Outcomes

MEDIUM

Trace the file-reading program for two inputs: first, a valid filename that exists; second, a filename that does not exist. For each input, list which statements run, whether the except block runs, whether the for loop runs, and what the user sees.

Hints
  • For an existing file, open() succeeds and fhand receives the file object.
  • For a missing file, open() raises FileNotFoundError.
  • Remember that exit() prevents the later loop and result print from running after the failure.
Situationopen()except blockLater loop and result
Filename existsSucceeds; fhand is assignedSkippedRun
Filename does not existRaises FileNotFoundErrorRuns, prints feedback, then calls exit()Do not run

The two control-flow outcomes for the file-opening operation.

Reliable File-Opening Practice

Place the file-opening operation in a try block, catch the opening failure in an except block, print a message that names the file, and call exit() when the rest of the program depends on the file being opened. This sequence keeps the failure from becoming an unexplained crash and prevents later code from using an unopened file.

  1. The main debugging question is not only whether an operation failed, but where control went afterward. For a successful opening, execution continues with file processing. For a failed opening, execution moves to recovery code, gives the user useful feedback, and exits before later file-dependent code runs.

Key Takeaways

  • Opening a file is an assumption and a potential point of failure.
  • A successful open() assigns the file object and allows later file-processing code to run.
  • A failed open() raises FileNotFoundError and transfers control to the except block.
  • The except block should provide a user-friendly message that identifies the filename.
  • When file opening is critical, exit() prevents later code from using an unopened file.