Python try, except, and else Statements
Learn how Python try, except, and else statements handle expected errors, validate input, and run code only after a risky operation succeeds.
Python programs sometimes encounter conditions they cannot complete normally. A user may enter letters when a number is expected, a file may be missing, or a conversion may receive an invalid value. These events are called exceptions.
An exception is an event raised during execution that changes normal control flow, often because an operation cannot be completed. Without a handler, an unhandled exception propagates outward through the program and may stop it.
Exception handling lets you respond to anticipated failures instead of allowing the program to terminate unexpectedly. Python uses a try block for code that may fail and an except clause for handling a particular failure.
Before continuing, it helps to understand Python error types, user input, and if/else statements.
The try, except, and else Structure
The general structure is:
try:
# Code that may raise an exception
except SomeException:
# Code that handles that exception
else:
# Code that runs only when try succeeds
The else clause is optional. It belongs to the try statement, not to an if statement. Each block is identified by a colon and indentation.
A complete statement can contain one or more except clauses:
try:
result = operation()
except FirstError:
handle_first_error()
except SecondError:
handle_second_error()
else:
use_successful_result()
The names in this example are placeholders. In real code, replace them with an operation and exception types that make sense for the task.
How Execution Flows
Python first runs the statements in try. What happens next depends on whether an exception is raised.
| What happens in try | Does a matching except run? | Does else run? | Result |
|---|---|---|---|
| No exception occurs | No | Yes | The success path runs, then execution continues after the construct. |
| A matching exception occurs | Yes | No | The matching handler runs. Afterward, execution continues after the construct unless the handler raises another exception. |
| A nonmatching exception occurs | No | No | The exception propagates outward because these handlers do not match it. |
| An exception occurs inside else | No, not from the preceding clauses | It started, but does not finish normally | The preceding handlers do not catch it because the try block has already completed. |
Normal execution continues after the complete try statement when no exception remains unhandled. An unhandled exception instead continues through calling code; this process is called exception propagation.
Catch Specific Exceptions
Prefer naming the exception you expect:
text = input("Enter a whole number: ")
try:
number = int(text)
except ValueError:
print("Please enter digits for a whole number.")
else:
print("You entered", number)
int() converts suitable input into an integer. If the text cannot represent an integer, it raises ValueError, which means a function received a value of an inappropriate form for the requested operation.
A named handler is preferable to a bare except:
# Usually too broad
try:
number = int(text)
except:
print("Something went wrong")
A bare except has no named exception type and catches almost every exception. It can conceal programming mistakes and unexpected failures. It may also catch events such as keyboard interrupts and system exits, making it harder for a program or its user to stop it normally. Catch expected failures narrowly, such as except ValueError:, and allow unrelated defects to remain visible.
Multiple handlers are useful when different errors need different responses:
try:
value = int(input("Enter a number: "))
except ValueError:
print("That was not valid integer text.")
except TypeError:
print("The conversion received an invalid object.")
else:
print("Conversion succeeded:", value)
Why Use else?
Use else for code that should run only after every statement in try succeeds. This keeps the risky part small and separates error handling from success-dependent work.
user_text = input("Enter a number: ")
try:
number = int(user_text)
except ValueError:
print("Invalid integer text.")
else:
doubled = number * 2
print("Doubled:", doubled)
Here, only the conversion is in try. The calculation and output require a successful conversion, so they are in else. If the calculation later has a different possible failure, it is not automatically handled by the preceding except ValueError.
Do not use exceptions as a replacement for ordinary decisions. After a value has been converted successfully, use if, elif, and else to evaluate business rules such as whether a number is large enough.
Interactive Age Validation Example
This program reads age-like text, converts it to an integer, handles invalid numeric text, and then applies a rule requiring an age of at least 21.
age_text = input("Enter your age: ")
try:
age = int(age_text)
except ValueError:
print("Invalid input: enter a whole number.")
else:
if age < 0:
print("Age cannot be negative.")
elif age >= 21:
print("You meet the 21-or-older requirement.")
else:
print("You are below the 21-year threshold.")
print("Program finished.")
input() always returns text. The conversion can therefore fail before the age rule is evaluated. The conditional checks inside else run only after int(age_text) succeeds.
| User entry | int() outcome | Handler or success path | Age-rule outcome |
|---|---|---|---|
Nonnumeric text such as a | Raises ValueError | except ValueError displays an invalid-input message. | The age rule does not run. |
Number at or above the threshold, such as 25 | Returns integer 25 | else runs. | The person meets the 21-or-older rule. |
Number below the threshold, such as 13 | Returns integer 13 | else runs. | The person is below the threshold. |
| Empty input | Raises ValueError | except ValueError displays an invalid-input message. | The age rule does not run. |
Successful conversion does not guarantee sensible domain data. For example, -4 is valid integer text but is not a sensible age. The first condition in else rejects it. You could also enforce an upper bound for implausible ages.
Integer Conversion and Validation Cases
entries = ["42", "3.5", ""]
for entry in entries:
try:
value = int(entry)
except ValueError:
print(entry, "cannot be converted by int()")
else:
print(entry, "becomes", value)
"42" converts successfully. Decimal-like text such as "3.5" and empty text such as "" raise ValueError when passed to int(). This demonstrates the difference between conversion validity and application validity: even a successfully converted integer may violate a rule such as a permitted age range.
Keep try Blocks Small
Put only failure-prone statements in try. A large block makes it unclear which operation caused the exception and can accidentally handle errors from unrelated code.
# Narrow and clear
try:
age = int(age_text)
except ValueError:
print("Enter a whole-number age.")
else:
message = make_age_message(age)
print(message)
In contrast, placing input conversion, calculations, file operations, and unrelated output in one try block makes a ValueError handler responsible for more code than necessary. Move success-only work to else or place unrelated work after the complete construct.
Write useful, user-facing messages for expected input errors. A message should explain what the user can do next rather than merely saying that an error occurred.
Common Problems
The program stops when text is entered instead of a number
int() raises ValueError when no matching handler exists. Wrap the conversion in try and add except ValueError with a clear recovery message.
Success-only logic runs after invalid input
The logic may be after the entire construct or may use a variable that was never assigned because conversion failed. Place processing that depends on successful conversion inside else.
An except clause hides unexpected errors
A bare except catches more than the expected input failure. Replace it with a specific handler such as except ValueError:.
An error in else is not caught by the preceding except
The except clauses apply to statements in the associated try block. They do not cover statements in else. If an operation in else can fail and needs handling, give that operation an appropriately scoped try statement or redesign the code.
A negative age is accepted
Conversion checks the format, not whether the value makes sense for your application. Add an if condition in else to enforce nonnegative values and any reasonable upper limit.
finally and Related Clauses
Python also supports an optional finally clause. It is intended for cleanup code that should run whether or not an exception occurs, such as releasing a resource. Its detailed behavior is separate from the success-only purpose of else; see try, except, and finally statements.
Key Points
- An exception is a runtime event that changes normal control flow.
- The
tryblock contains code that may fail. - A specific
exceptclause handles an expected exception type, such asValueError. - The optional
elseclause runs only when the associatedtryblock finishes without an exception. - Keep
tryblocks narrow and put success-dependent work inelse. - Use ordinary conditional logic for valid values that do not satisfy an application rule.
- Successful conversion does not prove that data is sensible; domain validation may still be required.
- Avoid bare
exceptclauses unless broad catching is deliberately justified.
For the closely related syntax, continue with Python try and except statements or catching specific exceptions.