Try, except, else, finally in Python (Exception handling) | note.nkmk.me (2024)

In Python, try and except are used to handle exceptions. Additionally, else and finally can be used to define actions to take at the end of the try-except process.

Contents

  • Basic exception handling in Python: try ... except ...
    • Catch a specific exception
    • Store the exception object
    • Work with base classes
    • Flow when an exception occurs
  • Catch multiple exceptions
    • Apply different operations to multiple exceptions
    • Apply the same operation to multiple exceptions
  • Catch all exceptions
    • Wildcard except (Bare except)
    • Base class: Exception
  • Execute action if no exception occurs: try ... except ... else ...
  • Clean-up action: try ... except ... finally ...
  • Ignore exceptions: pass
  • Practical example: Reading image files
    • Without exception handling
    • With exception handling

You can also set up debugging assertions with the assert statement.

  • The assert statement in Python

Basic exception handling in Python: try ... except ...

Catch a specific exception

For example, when attempting division by zero, a ZeroDivisionError is raised, causing the process to end.

# print(1 / 0)# ZeroDivisionError: division by zero

To catch this exception, use try and except as follows:

try: print(1 / 0)except ZeroDivisionError: print('Error')# Error

Store the exception object

By using except <exception-name> as <variable-name>:, the exception object is stored in the variable. You can choose any name for the variable, but names like e and err are commonly used.

The exception object contains error messages that are displayed when an exception occurs, allowing you to check the error details by outputting them.

try: print(1 / 0)except ZeroDivisionError as e: print(e) print(type(e))# division by zero# <class 'ZeroDivisionError'>

In Python 2, it should be written as except <exception-name>, <variable-name>:.

Work with base classes

You can also specify a base class. For example, ArithmeticError is the base class for ZeroDivisionError. The variable stores the exception object of the derived class that actually occurred.

print(issubclass(ZeroDivisionError, ArithmeticError))# Truetry: print(1 / 0)except ArithmeticError as e: print(e) print(type(e))# division by zero# <class 'ZeroDivisionError'>

Check the official documentation for built-in exceptions in Python.

Flow when an exception occurs

When an exception occurs in the try clause, the subsequent code in the try clause is skipped.

For example, if an exception occurs in the middle of the for loop, the loop ends at that point, and the code in the except clause is executed.

try: for i in [-2, -1, 0, 1, 2]: print(1 / i)except ZeroDivisionError as e: print(e)# -0.5# -1.0# division by zero

You can specify the code to execute after the except clause using the else and finally clauses, which will be described later.

Catch multiple exceptions

Define the following function that catches ZeroDivisionError.

def divide(a, b): try: print(a / b) except ZeroDivisionError as e: print('catch ZeroDivisionError:', e)

This function can catch ZeroDivisionError, but it cannot catch other exceptions.

divide(1, 0)# catch ZeroDivisionError: division by zero# divide('a', 'b')# TypeError: unsupported operand type(s) for /: 'str' and 'str'

Apply different operations to multiple exceptions

You can use multiple except clauses to handle different exceptions with different operations.

def divide_each(a, b): try: print(a / b) except ZeroDivisionError as e: print('catch ZeroDivisionError:', e) except TypeError as e: print('catch TypeError:', e)divide_each(1, 0)# catch ZeroDivisionError: division by zerodivide_each('a', 'b')# catch TypeError: unsupported operand type(s) for /: 'str' and 'str'

Apply the same operation to multiple exceptions

You can specify multiple exception names in a single except clause by using a tuple.

def divide_same(a, b): try: print(a / b) except (ZeroDivisionError, TypeError) as e: print(e)divide_same(1, 0)# division by zerodivide_same('a', 'b')# unsupported operand type(s) for /: 'str' and 'str'

Catch all exceptions

You can also catch all exceptions without specifying them.

Wildcard except (Bare except)

All exceptions can be caught by omitting the exception name from the except clause. If there are multiple except clauses, the exception name can be omitted only in the last except clause.

The use of an except clause without specifying the exception name is referred to as a wildcard except or bare except, and as mentioned in the official documentation, caution should be exercised when using it.

The last except clause may omit the exception name(s), to serve as a wildcard. Use this with extreme caution, since it is easy to mask a real programming error in this way! 8. Errors and Exceptions - Handling Exceptions — Python 3.9.0 documentation

def divide_wildcard(a, b): try: print(a / b) except: print('Error')divide_wildcard(1, 0)# Errordivide_wildcard('a', 'b')# Error

Using a wildcard except, you can catch all exceptions, including SystemExit (raised by sys.exit(), etc.) and KeyboardInterrupt (triggered by pressing Ctrl + C). However, it's often preferable not to catch these particular exceptions. In such cases, using Exception instead may be a better option, as described next.

Base class: Exception

You can specify Exception in the except clause, which is the base class for all built-in, non-system-exiting exceptions.

def divide_exception(a, b): try: print(a / b) except Exception as e: print(e)divide_exception(1, 0)# division by zerodivide_exception('a', 'b')# unsupported operand type(s) for /: 'str' and 'str'

The class hierarchy for built-in exceptions is as follows.

BaseException ├── BaseExceptionGroup ├── GeneratorExit ├── KeyboardInterrupt ├── SystemExit └── Exception ├── StopAsyncIteration ├── StopIteration ├── ... ...

Since SystemExit and KeyboardInterrupt do not inherit from Exception, using Exception in the except clause will not catch sys.exit() or interrupts like Ctrl + C.

The base class for all built-in exceptions, including SystemExit and KeyboardInterrupt, is BaseException. If you specify BaseException instead of Exception in the except clause, all exceptions will be caught.

It is better to specify the expected exceptions in the except clause as much as possible, because catching an unexpected exception may lead to a bug.

Execute action if no exception occurs: try ... except ... else ...

You can use the else clause to specify an action to be executed if no exception occurs. If an exception does occur and is caught by an except clause, the action in the else clause will not be executed.

def divide_else(a, b): try: print(a / b) except ZeroDivisionError as e: print('catch ZeroDivisionError:', e) else: print('finish (no error)')divide_else(1, 2)# 0.5# finish (no error)divide_else(1, 0)# catch ZeroDivisionError: division by zero

Clean-up action: try ... except ... finally ...

In the finally clause, you can specify the clean-up action to be executed whether an exception occurs or not.

def divide_finally(a, b): try: print(a / b) except ZeroDivisionError as e: print('catch ZeroDivisionError:', e) finally: print('all finish')divide_finally(1, 2)# 0.5# all finishdivide_finally(1, 0)# catch ZeroDivisionError: division by zero# all finish

You can also use the else and finally clause together. 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)') finally: print('all finish')divide_else_finally(1, 2)# 0.5# finish (no error)# all finishdivide_else_finally(1, 0)# catch ZeroDivisionError: division by zero# all finish

Ignore exceptions: pass

If you want to catch an exception and continue without taking any action, use pass.

def divide_pass(a, b): try: print(a / b) except ZeroDivisionError: passdivide_pass(1, 0)

See the following article for details on the pass statement.

  • The pass statement in Python

Practical example: Reading image files

A convenient example of using exception handling is reading image files.

The following is an example of resizing image files in a folder using Pillow.

  • Resize images with Python, Pillow

Without exception handling

Get all file paths in the folder with glob() and resize only files that match specific extensions.

  • How to use glob() in Python
  • Get the filename, directory, extension from a path string in Python
  • The in operator in Python (for list, string, dictionary, etc.)
import osimport globfrom PIL import Imagedst_dir = 'data/temp/images_half'os.makedirs(dst_dir, exist_ok=True)
files = glob.glob('./data/temp/images/*')for f in files: root, ext = os.path.splitext(f) if ext in ['.jpg', '.png']: img = Image.open(f) img_resize = img.resize((img.width // 2, img.height // 2)) basename = os.path.basename(root) img_resize.save(os.path.join(dst_dir, basename + '_half' + ext))

Since image files can have various extensions, it is difficult to specify all of them.

With exception handling

files = glob.glob('./data/temp/images/*')for f in files: try: img = Image.open(f) img_resize = img.resize((img.width // 2, img.height // 2)) root, ext = os.path.splitext(f) basename = os.path.basename(root) img_resize.save(os.path.join(dst_dir, basename + '_half' + ext)) except OSError as e: pass

All files that can be opened with Pillow's Image.open() are resized.

The approach that explicitly checks the conditions, like in the first example, is called "LBYL: Look Before You Leap", while the approach that uses exception handling, like in the second example, is called "EAFP: Easier to Ask for Forgiveness than Permission".

  • Duck typing with hasattr() and abstract base class in Python

Both approaches have pros and cons, but using exception handling can make the code more concise when dealing with processes that involve many conditions.

Try, except, else, finally in Python (Exception handling) | note.nkmk.me (2024)

References

Top Articles
Latest Posts
Article information

Author: Moshe Kshlerin

Last Updated:

Views: 6274

Rating: 4.7 / 5 (57 voted)

Reviews: 80% of readers found this page helpful

Author information

Name: Moshe Kshlerin

Birthday: 1994-01-25

Address: Suite 609 315 Lupita Unions, Ronnieburgh, MI 62697

Phone: +2424755286529

Job: District Education Designer

Hobby: Yoga, Gunsmithing, Singing, 3D printing, Nordic skating, Soapmaking, Juggling

Introduction: My name is Moshe Kshlerin, I am a gleaming, attractive, outstanding, pleasant, delightful, outstanding, famous person who loves writing and wants to share my knowledge and understanding with you.