Concepts / Debugging and Error Handling

Debugging and Error Handling

Debugging is not only about reacting after a crash.

  • Programming

The Hidden Risk in Line Parsing

When a program parses a file line by line, it may split each line into words and then inspect particular words. The danger is that lines do not always have the same structure. A line may be empty, or it may contain only one word when the program expects more. Accessing a list index that does not exist causes an IndexError and crashes the program. Defensive control flow prevents the program from making that unsafe access.

Key point

The three techniques in this lesson work together: continue skips unwanted lines, guardian code checks that an access is safe, and or combines several skip conditions into one readable decision.

Skipping Unwanted Iterations

When parsing a file, you may care only about lines that begin with the word From. A continue statement handles the lines that do not qualify. When the condition for skipping is met, continue immediately jumps back to the top of the loop. The remaining statements in the current iteration are not executed, and the loop moves on to the next line.

Code walkthrough
for line in lines:
    words = line.split()
    if words[0] != "From":
        continue
    process_line(words)
  1. 1
    The loop receives a line.
  2. 2
    split creates a list of words from that line.
  3. 3
    The condition checks the first word.
  4. 4
    continue returns control to the next loop iteration when the first word is not From.
  5. 5
    The processing step runs only for a line whose first word is From.
  • Each iteration examines one line.
  • The line is split into a list of words.
  • A line whose first word is not From is skipped.
  • Only qualifying lines reach the processing step.
Read lineFirst word is FromcontinueNext iterationProcess lineNoYes
When a line does not meet the condition, what happens next?

Why the First Check Can Fail

What do you think happens?

What happens when an empty line reaches the expression words[0]?

Reveal answer
Answer:

The program raises an IndexError before it can execute continue.

An empty line produces no words, so there is no element at index 0. The program must check that the list contains an element before accessing words[0].

The continue statement cannot protect an expression that fails before the condition is evaluated. In the earlier pattern, words[0] is evaluated as part of the if condition. If words is empty, the program crashes while trying to obtain its first element. The missing step is a guardian check placed before the access it protects.

Guarding List Access

Guardian code is a defensive check that verifies whether an operation is safe before allowing it to happen. For a list of words, the program checks the list length before accessing an index. If the list is empty, continue skips the line. Only after this check succeeds may the program safely inspect words[0].

python
Worked example

Protecting the First-Word Check

A parser should process only lines whose first word is From, but some input lines may be empty.

  1. 1
    Split the line

    The line becomes a list named words.

  2. 2
    Check the length

    If len(words) is 0, the line has no first word, so continue skips it before any index access.

  3. 3
    Inspect the first word

    The expression words[0] is reached only after the guardian check confirms that an element exists.

  4. 4
    Skip or process

    A nonmatching first word causes another continue; a first word of From reaches the processing step.

Result

The parser avoids accessing a nonexistent first element and processes only lines that meet the required criterion.

wordsList length checked firstEmpty listSkip with continueIndex 0First word existsCheck Fromlength is 0length is greater than 0safe access
How does checking a list's length prevent access to an element that does not exist?

Combining Skip Conditions

Two separate if statements can both use continue: one for an empty list and one for a first word that is not From. This works, but the conditions can be combined. The or operator makes the complete condition true when at least one of its component conditions is true. Therefore, the line is skipped if it is empty or if its first word is not From.

python
len(words) == 0Empty listorCombine conditionswords[0] != FromNonmatching first wordcontinueSkip iterationEither condition true
How do multiple conditions combine, and when does the overall expression become true?
Line conditionOverall skip conditionResult
The list is emptyTrue or ...continue skips the line
The first word is not From... or Truecontinue skips the line
The list is not empty and the first word is FromFalse or FalseThe line reaches processing

The or expression is true when at least one skip condition is true.

A Complete Defensive Pattern

Code walkthrough
for line in lines:
    words = line.split()
    if len(words) == 0 or words[0] != "From":
        continue
    process_line(words)
  1. 1
    The parser starts with one line and creates its words list.
  2. 2
    The empty-list check is positioned before the first-word access.
  3. 3
    If the list is empty, the line is skipped immediately.
  4. 4
    If the list is not empty but its first word is not From, the line is also skipped.
  5. 5
    If neither skip condition is true, processing continues.
  • Read and split the current line.
  • The first condition protects the index access for empty lines.
  • The second condition filters out lines whose first word is not From.
  • continue skips the current iteration when either condition is true.
  • Only qualifying, nonempty lines are processed.

This pattern is compact without removing the safety check. The guardian condition comes first inside the compound expression, and the filtering condition follows it. The continue statement has one clear job: leave the current iteration whenever the line should not be processed.

Mistakes That Cause Crashes

  • Common mistake

    Accessing words[0] before checking whether the list has an element.

    What it looks like
    if words[0] != "From":
    Why it fails

    An empty line produces an empty list, so index 0 does not exist and the program raises IndexError.

    Do this instead

    Check the list length first, then access words[0] only when the list is not empty.

  • Common mistake

    Putting the guardian check after the protected access.

    What it looks like
    if words[0] != "From":
        continue
    if len(words) == 0:
        continue
    Why it fails

    The unsafe access has already happened before the length check can help.

    Do this instead

    Place the guardian check before every access it protects.

  • Common mistake

    Processing every line without filtering.

    What it looks like
    for line in lines:
        process_line(line)
    Why it fails

    Lines that do not meet the required criterion are processed instead of being skipped.

    Do this instead

    Use continue to move immediately to the next iteration when a line does not qualify.

  • Common mistake

    Repeating separate skip blocks when one compound condition is clearer.

    What it looks like
    if len(words) == 0:
        continue
    if words[0] != "From":
        continue
    Why it fails

    The logic works, but combining related skip conditions can reduce duplication and improve readability.

    Do this instead

    Use one if statement with or when either condition should cause the same continue action.

Practice the Control Flow

MEDIUM

Rewrite a line-parsing loop so that it processes only nonempty lines whose first word is From. Use one compound if statement with or and place continue in that statement.

Hints
  • Split each line into a list named words.
  • The first condition should identify an empty list.
  • The second condition should identify a first word that is not From.
  • Both conditions should lead to the same continue statement.
Worked example

Tracing Three Kinds of Lines

Predict the control-flow result for an empty line, a line beginning with To, and a line beginning with From.

  1. 1
    Empty line

    Splitting produces no words. The length condition is true, so continue skips the iteration before words[0] is accessed.

  2. 2
    Line beginning with To

    The list is not empty, but the first word is not From. The second condition is true, so continue skips the iteration.

  3. 3
    Line beginning with From

    The list is not empty and the first word is From. Both skip conditions are false, so the line reaches processing.

Result

Only the line beginning with From reaches the processing step, while the empty and nonmatching lines are skipped safely.

Reliable Parsing Habits

  • Identify which lines your parser actually needs to process.
  • Use continue to leave an iteration as soon as a line fails the required criterion.
  • Check a list's length before accessing an index.
  • Place guardian checks before the code they protect.
  • Combine skip conditions with or when either condition should produce the same result.
  • Test with empty lines and lines containing fewer words than expected.

Debugging is not only about reacting after a crash. In this pattern, error handling is built into the control flow: unsafe input is recognized early, the current iteration is abandoned, and only data that passes the checks is processed.

Key Takeaways

  • continue immediately moves control to the next loop iteration, skipping the remaining statements for the current line.
  • Accessing a nonexistent list index can raise IndexError, especially when parsing empty or inconsistently structured lines.
  • Guardian code checks the list length before an index is accessed.
  • The or operator makes a combined skip condition true when at least one component condition is true.
  • Robust parsing places checks before protected operations and tests edge cases such as empty lines.

Related concepts

More concepts starting with D