The statements in the else block are executed if execution falls off the bottom of the try - if there was no exception. Honestly, I've never found a need.

However, Handling Exceptions notes:

The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try ... except statement.

So, if you have a method that could, for example, throw an IOError, and you want to catch exceptions it raises, but there's something else you want to do if the first operation succeeds, and you don't want to catch an IOError from that operation, you might write something like this:

try:
    operation_that_can_throw_ioerror()
except IOError:
    handle_the_exception_somehow()
else:
    # we don't want to catch the IOError if it's raised
    another_operation_that_can_throw_ioerror()
finally:
    something_we_always_need_to_do()

If you just put another_operation_that_can_throw_ioerror() after operation_that_can_throw_ioerror, the except would catch the second call's errors. And if you put it after the whole try block, it'll always be run, and not until after the finally. The else lets you make sure

  1. the second operation's only run if there's no exception,
  2. it's run before the finally block, and
  3. any IOErrors it raises aren't caught here
Answer from Blair Conrad on Stack Overflow
🌐
GeeksforGeeks
geeksforgeeks.org › python › try-except-else-and-finally-in-python
Try, Except, else and Finally in Python - GeeksforGeeks
Example: Let's try to throw the exception in except block and Finally will execute either exception will generate or not ... # Python code to illustrate # working of try() def divide(x, y): try: # Floor Division : Gives only Fractional # Part as Answer result = x // y except ZeroDivisionError: print("Sorry ! You are dividing by zero ") else: print("Yeah !
Published   July 15, 2025
🌐
W3Schools
w3schools.com › python › python_try_except.asp
Python Try Except
The except block lets you handle the error. The else block lets you execute code when there is no error. The finally block lets you execute code, regardless of the result of the try- and except blocks.
Discussions

Try Except Else question- when do you use Else?
As u/OskaRRRitoS said already: else is for running code if no exception is raised. Try to think of it as a way to minimize your try block. Sometimes you want to do additional stuff as a part of the try block, but you want to keep the try block as minimal and specific as possible. So you can put things into else that have to happen if try doesn't fail, but doesn't need to be caught by except. More on reddit.com
🌐 r/Python
48
35
October 15, 2022
python - Purpose of else and finally in exception handling - Stack Overflow
Are the else and finally sections of exception handling redundant? For example, is there any difference between the following two code snippets? try: foo = open("foo.txt") except IOError: ... More on stackoverflow.com
🌐 stackoverflow.com
When to use try-except-else-finally in Python
I think at minimum this could do with a better title (e.g. "what is try-except-else-finally in python"; but would really just benefit from more explanatory content/that actually answers the current title. It doesn't at all explain when to use try-except-else-finally, it simply described what the else part of try-except-else-finally is. For example, when would I actually want to use an else clause in there? There's no discussion or example of good times to use it. It simply describes that this is a language feature that exists. More on reddit.com
🌐 r/Python
9
11
February 4, 2023
exception - Is it a good practice to use try-except-else in Python? - Stack Overflow
Without the else-clause, the only option to run additional code before finalization would be the clumsy practice of adding the code to the try-clause. That is clumsy because it risks raising exceptions in code that wasn't intended to be protected by the try-block. More on stackoverflow.com
🌐 stackoverflow.com
Top answer
1 of 16
1149

The statements in the else block are executed if execution falls off the bottom of the try - if there was no exception. Honestly, I've never found a need.

However, Handling Exceptions notes:

The use of the else clause is better than adding additional code to the try clause because it avoids accidentally catching an exception that wasn’t raised by the code being protected by the try ... except statement.

So, if you have a method that could, for example, throw an IOError, and you want to catch exceptions it raises, but there's something else you want to do if the first operation succeeds, and you don't want to catch an IOError from that operation, you might write something like this:

try:
    operation_that_can_throw_ioerror()
except IOError:
    handle_the_exception_somehow()
else:
    # we don't want to catch the IOError if it's raised
    another_operation_that_can_throw_ioerror()
finally:
    something_we_always_need_to_do()

If you just put another_operation_that_can_throw_ioerror() after operation_that_can_throw_ioerror, the except would catch the second call's errors. And if you put it after the whole try block, it'll always be run, and not until after the finally. The else lets you make sure

  1. the second operation's only run if there's no exception,
  2. it's run before the finally block, and
  3. any IOErrors it raises aren't caught here
2 of 16
172

There is one big reason to use else - style and readability. It's generally a good idea to keep code that can cause exceptions near the code that deals with them. For example, compare these:

try:
    from EasyDialogs import AskPassword
    # 20 other lines
    getpass = AskPassword
except ImportError:
    getpass = default_getpass

and

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
else:
    # 20 other lines
    getpass = AskPassword

The second one is good when the except can't return early, or re-throw the exception. If possible, I would have written:

try:
    from EasyDialogs import AskPassword
except ImportError:
    getpass = default_getpass
    return False  # or throw Exception('something more descriptive')

# 20 other lines
getpass = AskPassword

Note: Answer copied from recently-posted duplicate here, hence all this "AskPassword" stuff.

🌐
Python documentation
docs.python.org › 3 › tutorial › errors.html
8. Errors and Exceptions — Python 3.14.3 documentation
If an exception occurs during execution of the try clause, the exception may be handled by an except clause. If the exception is not handled by an except clause, the exception is re-raised after the finally clause has been executed.
🌐
Python for Network Engineers
pyneng.readthedocs.io › en › latest › book › 06_control_structures › exceptions.html
Working with try/except/else/finally - Python for network engineers
# -*- coding: utf-8 -*- try: a = input("Enter first number: ") b = input("Enter second number: ") result = int(a)/int(b) except (ValueError, ZeroDivisionError): print("Something went wrong...") else: print("Result is squared: ", result``2) ... $ python divide_ver3.py Enter first number: 10 Enter second number: 2 Result is squared: 25 $ python divide_ver3.py Enter first number: werq Enter second number: 3 Something went wrong... Block finally is another optional block in try statement.
🌐
Medium
galea.medium.com › pythons-try-except-else-finally-explained-f04d47d57125
Python’s “try except else finally” explained | by Alex Galea | Medium
October 4, 2020 - Understanding else/finally is simple because there are only two cases. The try statement succeeds -> The except statement is skipped -> The else statement runs -> The finally statement runs
🌐
Note.nkmk.me
note.nkmk.me › home › python
Try, except, else, finally in Python (Exception handling) | note.nkmk.me
August 15, 2023 - If no exception occurs, the else clause is executed and then the finally clause is executed. def divide_else_finally(a, b): try: print(a / b) except ZeroDivisionError as e: print('catch ZeroDivisionError:', e) else: print('finish (no error)') ...
Find elsewhere
🌐
freeCodeCamp
freecodecamp.org › news › error-handling-in-python-introduction
Error Handling in Python – try, except, else, & finally Explained with Code Examples
April 11, 2024 - Back to my first example, I changed our variable x back to the value 0 and tried to divide 5 by x. This produces a ZeroDivisionError. Since my except statement specifies this type of exception, the code in that clause executes before the program resumes running as normal. Finally, if the program throws an exception in the try clause, but the exception is not specified in any except statements, then the program will:
🌐
Reddit
reddit.com › r/python › try except else question- when do you use else?
r/Python on Reddit: Try Except Else question- when do you use Else?
October 15, 2022 -

My understanding is that Else runs if Try succeeds without any exceptions. What are the uses for this where you couldn’t just put that code in the Try statement?

🌐
GeeksforGeeks
geeksforgeeks.org › python › python-exception-handling
Python Exception Handling - GeeksforGeeks
October 11, 2025 - Explanation: try block attempts division, except blocks catch specific errors, else block executes only if no errors occur, while finally block always runs, signaling end of execution.
🌐
GeeksforGeeks
geeksforgeeks.org › python › python-try-except
Python Try Except - GeeksforGeeks
July 23, 2025 - The final block always executes after the normal termination of the try block or after the try block terminates due to some exceptions. ... try: # Some Code except: # Executed if error in the # try block else: # execute if no exception finally: ...
🌐
Programiz
programiz.com › python-programming › exception-handling
Python Exception Handling (With Examples)
The finally block is optional. And, for each try block, there can be only one finally block. ... try: numerator = 10 denominator = 0 result = numerator/denominator print(result) except: print("Error: Denominator cannot be 0.") finally: print("This is finally block.")
🌐
MSSQLTips
mssqltips.com › home › python exception handling with try, except, else, finally clause
Python Exception Handling with Try, Except, Else, Finally Clause
June 10, 2022 - It does not change the behavior of the try/except block itself, however, the code under finally will be executed in all situations, regardless of if an exception occurred and it was handled, or no exception occurred at all: try: # block of code except: # error message else: # executed if no exception occurred finally #executed regardless if an exception occurred or not
🌐
Reddit
reddit.com › r/python › when to use try-except-else-finally in python
r/Python on Reddit: When to use try-except-else-finally in Python
February 4, 2023 - Unlike many other languages and according to some popular coding suggestion guides the try block should be just the line(s) of code that can throw the exception you are catching; the else is what to do if the exception didn't occur.
🌐
w3resource
w3resource.com › python › python-try-except-with-examples.php
Python Try-Except with Examples: Else, Finally, and More
The 'try' block attempts to convert user input to an integer and divide it. The 'except' blocks handle potential errors. The 'else' block runs only if no exceptions occur. The 'finally' block runs at the end, no matter what.
🌐
Python Tutorial
pythontutorial.net › home › python basics › python try…except…finally
Python try...except...finally Statement - Python Tutorial
March 30, 2025 - The try clause in the following example doesn’t cause an error. Therefore, all statements in the try and finally clauses execute: a = 10 b = 2 try: c = a / b print(c) except ZeroDivisionError as error: print(error) finally: print('Finishing up.') Code language: PHP (php)
🌐
Inventive HQ
inventivehq.com › home › blog › automation › python try except: complete error handling guide
Python Error Handling: Try, Except, Finally, and Else
November 6, 2025 - except runs when an error occurs. else runs only if no error occurred. finally always runs, whether there was an error or not. Use finally for cleanup that must happen regardless of success or failure—closing files, database connections, or ...
Top answer
1 of 11
871

"I do not know if it is out of ignorance, but I do not like that kind of programming, as it is using exceptions to perform flow control."

In the Python world, using exceptions for flow control is common and normal.

Even the Python core developers use exceptions for flow-control and that style is heavily baked into the language (i.e. the iterator protocol uses StopIteration to signal loop termination).

In addition, the try-except-style is used to prevent the race-conditions inherent in some of the "look-before-you-leap" constructs. For example, testing os.path.exists results in information that may be out-of-date by the time you use it. Likewise, Queue.full returns information that may be stale. The try-except-else style will produce more reliable code in these cases.

"It my understanding that exceptions are not errors, they should only be used for exceptional conditions"

In some other languages, that rule reflects their cultural norms as reflected in their libraries. The "rule" is also based in-part on performance considerations for those languages.

The Python cultural norm is somewhat different. In many cases, you must use exceptions for control-flow. Also, the use of exceptions in Python does not slow the surrounding code and calling code as it does in some compiled languages (i.e. CPython already implements code for exception checking at every step, regardless of whether you actually use exceptions or not).

In other words, your understanding that "exceptions are for the exceptional" is a rule that makes sense in some other languages, but not for Python.

"However, if it is included in the language itself, there must be a good reason for it, isn't it?"

Besides helping to avoid race-conditions, exceptions are also very useful for pulling error-handling outside loops. This is a necessary optimization in interpreted languages which do not tend to have automatic loop invariant code motion.

Also, exceptions can simplify code quite a bit in common situations where the ability to handle an issue is far removed from where the issue arose. For example, it is common to have top level user-interface code calling code for business logic which in turn calls low-level routines. Situations arising in the low-level routines (such as duplicate records for unique keys in database accesses) can only be handled in top-level code (such as asking the user for a new key that doesn't conflict with existing keys). The use of exceptions for this kind of control-flow allows the mid-level routines to completely ignore the issue and be nicely decoupled from that aspect of flow-control.

There is a nice blog post on the indispensibility of exceptions here.

Also, see this Stack Overflow answer: Are exceptions really for exceptional errors?

"What is the reason for the try-except-else to exist?"

The else-clause itself is interesting. It runs when there is no exception but before the finally-clause. That is its primary purpose.

Without the else-clause, the only option to run additional code before finalization would be the clumsy practice of adding the code to the try-clause. That is clumsy because it risks raising exceptions in code that wasn't intended to be protected by the try-block.

The use-case of running additional unprotected code prior to finalization doesn't arise very often. So, don't expect to see many examples in published code. It is somewhat rare.

Another use-case for the else-clause is to perform actions that must occur when no exception occurs and that do not occur when exceptions are handled. For example:

recip = float('Inf')
try:
    recip = 1 / f(x)
except ZeroDivisionError:
    logging.info('Infinite result')
else:
    logging.info('Finite result')

Another example occurs in unittest runners:

try:
    tests_run += 1
    run_testcase(case)
except Exception:
    tests_failed += 1
    logging.exception('Failing test case: %r', case)
    print('F', end='')
else:
    logging.info('Successful test case: %r', case)
    print('.', end='')

Lastly, the most common use of an else-clause in a try-block is for a bit of beautification (aligning the exceptional outcomes and non-exceptional outcomes at the same level of indentation). This use is always optional and isn't strictly necessary.

2 of 11
215

What is the reason for the try-except-else to exist?

A try block allows you to handle an expected error. The except block should only catch exceptions you are prepared to handle. If you handle an unexpected error, your code may do the wrong thing and hide bugs.

An else clause will execute if there were no errors, and by not executing that code in the try block, you avoid catching an unexpected error. Again, catching an unexpected error can hide bugs.

Example

For example:

try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
else:
    return something

The "try, except" suite has two optional clauses, else and finally. So it's actually try-except-else-finally.

else will evaluate only if there is no exception from the try block. It allows us to simplify the more complicated code below:

no_error = None
try:
    try_this(whatever)
    no_error = True
except SomeException as the_exception:
    handle(the_exception)
if no_error:
    return something

so if we compare an else to the alternative (which might create bugs) we see that it reduces the lines of code and we can have a more readable, maintainable, and less buggy code-base.

finally

finally will execute no matter what, even if another line is being evaluated with a return statement.

Broken down with pseudo-code

It might help to break this down, in the smallest possible form that demonstrates all features, with comments. Assume this syntactically correct (but not runnable unless the names are defined) pseudo-code is in a function.

For example:

try:
    try_this(whatever)
except SomeException as the_exception:
    handle_SomeException(the_exception)
    # Handle a instance of SomeException or a subclass of it.
except Exception as the_exception:
    generic_handle(the_exception)
    # Handle any other exception that inherits from Exception
    # - doesn't include GeneratorExit, KeyboardInterrupt, SystemExit
    # Avoid bare `except:`
else: # there was no exception whatsoever
    return something()
    # if no exception, the "something()" gets evaluated,
    # but the return will not be executed due to the return in the
    # finally block below.
finally:
    # this block will execute no matter what, even if no exception,
    # after "something" is eval'd but before that value is returned
    # but even if there is an exception.
    # a return here will hijack the return functionality. e.g.:
    return True # hijacks the return in the else clause above

It is true that we could include the code in the else block in the try block instead, where it would run if there were no exceptions, but what if that code itself raises an exception of the kind we're catching? Leaving it in the try block would hide that bug.

We want to minimize lines of code in the try block to avoid catching exceptions we did not expect, under the principle that if our code fails, we want it to fail loudly. This is a best practice.

It is my understanding that exceptions are not errors

In Python, most exceptions are errors.

We can view the exception hierarchy by using pydoc. For example, in Python 2:

$ python -m pydoc exceptions

or Python 3:

$ python -m pydoc builtins

Will give us the hierarchy. We can see that most kinds of Exception are errors, although Python uses some of them for things like ending for loops (StopIteration). This is Python 3's hierarchy:

BaseException
    Exception
        ArithmeticError
            FloatingPointError
            OverflowError
            ZeroDivisionError
        AssertionError
        AttributeError
        BufferError
        EOFError
        ImportError
            ModuleNotFoundError
        LookupError
            IndexError
            KeyError
        MemoryError
        NameError
            UnboundLocalError
        OSError
            BlockingIOError
            ChildProcessError
            ConnectionError
                BrokenPipeError
                ConnectionAbortedError
                ConnectionRefusedError
                ConnectionResetError
            FileExistsError
            FileNotFoundError
            InterruptedError
            IsADirectoryError
            NotADirectoryError
            PermissionError
            ProcessLookupError
            TimeoutError
        ReferenceError
        RuntimeError
            NotImplementedError
            RecursionError
        StopAsyncIteration
        StopIteration
        SyntaxError
            IndentationError
                TabError
        SystemError
        TypeError
        ValueError
            UnicodeError
                UnicodeDecodeError
                UnicodeEncodeError
                UnicodeTranslateError
        Warning
            BytesWarning
            DeprecationWarning
            FutureWarning
            ImportWarning
            PendingDeprecationWarning
            ResourceWarning
            RuntimeWarning
            SyntaxWarning
            UnicodeWarning
            UserWarning
    GeneratorExit
    KeyboardInterrupt
    SystemExit

A commenter asked:

Say you have a method which pings an external API and you want to handle the exception at a class outside the API wrapper, do you simply return e from the method under the except clause where e is the exception object?

No, you don't return the exception, just reraise it with a bare raise to preserve the stacktrace.

try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
    raise

Or, in Python 3, you can raise a new exception and preserve the backtrace with exception chaining:

try:
    try_this(whatever)
except SomeException as the_exception:
    handle(the_exception)
    raise DifferentException from the_exception

I elaborate in my answer here.

🌐
CodingNomads
codingnomads.com › python-try-except-else
Python: Try Except Else
The code inside the finally block will always run, no matter what happened before: try: pass # Try some code except: pass # Handle the exception(s) else: pass # Do something only if no exception has been raised finally: pass # Do something whether ...