Nested Exception Handling Statements in Python
Learn nested exception handling in Python with age validation, retry prompts, while loops, Boolean flags, ValueError, and clearer break/continue patterns.
When a Python program reads data from a user, the input may not have the expected form. For example, input() always returns a string, so converting that string with int() can fail if the user enters letters.
This lesson combines exception handling with a while loop so a program can report invalid input and decide whether to try again instead of terminating.
Nested exception handling statements means using exception-handling operations as part of a larger control-flow structure, such as a loop containing one or more input-validation steps.
Prerequisites and Key Terms
- Exception: A runtime event or error that interrupts normal program flow unless it is handled.
- Exception handling: Code that catches and responds to anticipated runtime errors.
- try block: The block containing code that may raise an exception.
- except block: The block that runs when a matching exception occurs.
- ValueError: The exception commonly raised when
int()receives text that cannot be converted to an integer. - input(): A function that reads user input as a string.
- int(): A conversion function that turns a valid numeric string into an integer.
- while loop: A loop that repeats while its condition remains true.
- Boolean flag: A
TrueorFalsevariable used to control whether a loop continues. - Conditional statement: An
if/elsedecision that selects different actions based on a condition.
Why Put Exception Handling Inside a Loop?
A basic input program might stop immediately when conversion fails:
age = int(input("Enter your age: "))
print(f"Your age is {age}.")
If the user enters twenty, int() raises ValueError. Since there is no matching handler, the program terminates.
Exception handling lets the program recover:
try:
age = int(input("Enter your age: "))
print(f"Your age is {age}.")
except ValueError:
print("Please enter your age as a whole number.")
This handles the error and notifies the user. It does not, by itself, decide whether another attempt should happen. Retry behavior is a separate control-flow decision, usually implemented with a loop and a condition.
Retrying with a Boolean Control Variable
A Boolean flag can control a loop. The flag starts as True, so the first attempt runs. Later code changes it to False when the interaction should end.
keep_trying = True
while keep_trying:
print("This attempt is running.")
keep_trying = False
The while keep_trying condition is evaluated before each iteration. When the flag becomes False, the loop stops before another iteration begins.
Age Input with a Retry Prompt
The following example places age conversion in one try block and places the retry-command conversion in a separate try block. The retry question appears only after an invalid age, which avoids asking a successful user whether to restart.
keep_trying = True
while keep_trying:
try:
age = int(input("Enter your age: "))
print(f"You entered age {age}.")
keep_trying = False
except ValueError:
print("Invalid age: please enter a whole number.")
try:
retry = int(input("Enter 0 to try again, or another number to exit: "))
except ValueError:
print("The retry command was not a number. Exiting.")
keep_trying = False
else:
if retry == 0:
keep_trying = True
else:
print("Exiting without another attempt.")
keep_trying = False
The outer control structure is the while loop. Inside it, the first try/except handles age conversion. If age conversion fails, a second input step runs. That second step has its own try/except because the retry response also needs conversion.
What Each Part Does
keep_trying = Truepermits the first loop iteration.int(input("Enter your age: "))reads text and attempts integer conversion.except ValueErrorcatches non-numeric age input.- The correction message tells the user what form is required.
- The retry prompt asks for a numeric command.
- A retry value of
0means start another age attempt. - Another valid integer means exit.
- A non-numeric retry response raises another
ValueError, which is handled by the inner handler and causes an exit.
Input Outcomes and Program Behavior
| Input stage | User input | Conversion result | Exception handled | Message or action | Loop outcome |
|---|---|---|---|---|---|
| Age prompt | 42 | age becomes 42 | None | Print the accepted age | Flag becomes False; stop |
| Age prompt | abc | Conversion fails | ValueError | Ask for a whole number, then show retry prompt | Depends on retry response |
| Retry prompt | 0 | retry becomes 0 | None | Choose restart | Next iteration begins |
| Retry prompt | 1 | retry becomes 1 | None | Print exit message | Flag becomes False; stop |
| Retry prompt | again | Conversion fails | ValueError | Print an exit-oriented message | Flag becomes False; stop |
Choosing the Exception Type
Use the narrowest exception type that describes the failure you expect. Since invalid text passed to int() raises ValueError, this is the appropriate handler:
try:
retry = int(input("Enter 0 to retry: "))
except ValueError:
print("Please use a number.")
| Clause | What it catches | Appropriate use | Caution |
|---|---|---|---|
except ValueError | Value-related failures such as invalid integer text | Expected failures from int() | It does not catch unrelated exception types |
Bare except | Nearly every exception, including many unexpected ones | Rare cases where broad interception is deliberately required | It can hide programming mistakes and interrupt signals |
except Exception | Most ordinary runtime exceptions | Controlled top-level fallback or logging when broad handling is intentional | Still too broad for a known numeric-conversion failure |
A bare except may appear in simple older examples, but it is usually a poor choice here. Replace it with except ValueError for invalid numeric retry commands. If several specific failures are expected, handle those intended exception types explicitly.
Control-Flow Walkthroughs
Non-numeric Age Followed by a Non-numeric Retry Response
- The loop condition is checked.
keep_tryingisTrue, so the iteration starts. - The age
tryblock callsinput()and thenint(). - If the user enters
old, conversion raisesValueError. - Python skips the rest of that
tryblock and runs itsexcept ValueErrorblock. - The program prints the correction message and asks for a retry command.
- If the user enters
maybe, the innerint()call raisesValueError. - The inner
except ValueErrorprints an exit message and sets the flag toFalse. - The loop reaches its end. Its next condition check is false, so no new age attempt runs.
Non-numeric Age Followed by 0
- The age conversion raises
ValueError, so the outer age handler runs. - The retry prompt receives
0; conversion succeeds. - The
if retry == 0condition is true. - The program leaves the handler with
keep_tryingstill true. - The loop checks its condition and begins another iteration.
- The user can now enter a valid age, such as
27. - The age conversion succeeds, the valid-age message prints, and the flag becomes
False. - The next loop check ends the interaction.
Valid Age Input
- The age
tryblock converts the input successfully. - No
exceptblock runs because no exception occurred. - The success message prints and the flag is set to
False. - The retry prompt is not reached because it is inside the age
exceptblock. - The loop ends on its next condition check.
Separating Validation from Retry Decisions
Age validation and retry selection are different decisions. Keeping them in separate blocks makes the program easier to read:
- The age
tryblock answers: “Can this input be converted to an integer?” - The age
exceptblock answers: “What should happen when conversion fails?” - The retry
tryblock answers: “Is the retry command itself a valid integer?” - The retry
ifstatement answers: “Does the valid command mean restart or exit?”
Do not place a retry prompt outside the branch where it belongs without deciding what it should mean after a successful age. Otherwise, users may be asked whether to restart even though the age was valid.
A Clearer Version with continue and break
A Boolean flag is useful for learning loop state, but explicit loop control can make the intended exits clearer. continue immediately starts the next iteration, while break ends the loop.
while True:
try:
age = int(input("Enter your age: "))
except ValueError:
print("Invalid age: please enter a whole number.")
try:
retry = int(input("Enter 0 to try again, or another number to exit: "))
except ValueError:
print("The retry command was not a number. Exiting.")
break
if retry == 0:
continue
print("Exiting without another attempt.")
break
else:
print(f"You entered age {age}.")
break
Here, continue is reached only when the retry value is 0. The loop returns directly to its condition check, which is always true for while True, and begins another attempt. Every exit path uses break.
Common Problems and Fixes
The Program Stops When Letters Are Entered for an Age
The int() conversion is probably outside a try block, or the code does not catch ValueError. Put the conversion inside try and display a validation message in except ValueError.
The Loop Keeps Running After the User Chooses to Exit
The Boolean flag may never be changed to False, or the exit branch may be missing break. Check every exit path. With the Boolean design, update the flag; with the clearer alternative, use break.
An Invalid Retry Response Behaves Unexpectedly
The retry conversion may be unhandled, or a broad exception clause may obscure the actual problem. Catch ValueError specifically and define the behavior, such as printing an exit message and stopping.
A Bare except Hides a Programming Mistake
A bare handler can catch errors unrelated to user input, making debugging difficult. Use the narrowest expected type, normally ValueError for failed integer conversion.
The User Is Asked to Restart After a Valid Age
The retry prompt is likely outside the invalid-input branch. If retry confirmation should occur only after an error, put the prompt inside the age except block or use the separate validation structure shown above.
Exam-Relevant Notes
input()returns a string, even when the user types digits.int("25")succeeds, butint("twenty-five")raisesValueError.- Only a matching
exceptblock runs when an exception occurs. - If no exception occurs, the matching
exceptblock is skipped. - An
ifstatement can choose between retry and exit after a successful retry-command conversion. - A loop condition controls whether another iteration begins; handling an exception does not automatically repeat the loop.
- Specific exception handlers are safer and clearer than bare
exceptclauses. - Indentation determines whether the retry prompt runs only after an invalid age or after every age attempt.
Summary
Nested exception handling combines a loop, one or more try/except blocks, and conditional decisions. Protect numeric conversions with except ValueError, explain invalid input clearly, and use a Boolean flag or explicit break/continue statements to control retries. Treat error handling, user notification, and retry selection as separate responsibilities so the resulting input flow remains predictable.