I’ve Been Scolded For Using “except Exception as e” in Python Before


^ but isn’t this how the except keyword works?

Yes, but the code can be written better

^ one issue with except Exception as e is that it catches every single Exception, and handles it the exact same way.

The hierarchy of Exceptions

  • BaseException is at the very top
  • Exception inherits from BaseException
  • Most other exceptions inherit from Exception eg ArithmeticError, AssertionError, AttributeError etc

We can check this on our own using the .__subclasses__() method

print(BaseException.__subclasses__())

'''
[<class 'BaseExceptionGroup'>, <class 'Exception'>, 
<class 'GeneratorExit'>, <class 'KeyboardInterrupt'>, 
<class 'SystemExit'>]
'''        
print(Exception.__subclasses__())

'''
[<class 'ArithmeticError'>, <class 'AssertionError'>, 
<class 'AttributeError'>, <class 'BufferError'>, <class 'EOFError'>, 
<class 'ImportError'>, <class 'LookupError'>, <class 'MemoryError'>, 
<class 'NameError'>, <class 'OSError'>, <class 'ReferenceError'>, 
<class 'RuntimeError'>, <class 'StopAsyncIteration'>, 
<class 'StopIteration'>, <class 'SyntaxError'>, <class 'SystemError'>, 
<class 'TypeError'>, <class 'ValueError'>, <class…        
<class 'ValueError'>, <class 'Warning'>, ...]
        

Why is “except Exception as e” problematic?

Using except Exception as e can be problematic because it catches all exceptions derived from Exception, including those you might not intend to handle in the same way. This can mask bugs, make debugging harder, and lead to unintended behavior. For instance, it will catch exceptions like KeyboardInterrupt or SystemExit, which are usually meant to signal that the program should stop running.

Better Exception Handling Practices

1. Be Specific with Exception Types

Instead of catching all exceptions, be specific about the types of exceptions you expect and know how to handle. This makes your code more predictable and easier to debug.

try:
    result = some_function()
except ValueError as ve:
    print(f"Value error occurred: {ve}")
except TypeError as te:
    print(f"Type error occurred: {te}")
        

2. Use the Finally Block

The finally block can be used to ensure that some code runs no matter what, even if an exception occurs. This is useful for cleaning up resources, such as closing files or network connections.

try:
    file = open('example.txt', 'r')
    data = file.read()
except FileNotFoundError as fnfe:
    print(f"File not found: {fnfe}")
finally:
    if file:
        file.close()
        

3. Avoid Bare Except Clauses

Avoid using a bare except clause, which catches all exceptions, including those you don’t intend to catch. Instead, use specific exceptions or at least except Exception.

try:
    some_risky_operation()
except Exception as e:
    print(f"An error occurred: {e}")
        

4. Log Exceptions Appropriately

Logging exceptions instead of printing them can be beneficial for debugging and tracking issues in production environments. Python’s logging module is useful for this purpose.

import logging

logging.basicConfig(level=logging.ERROR)

try:
    result = risky_operation()
except Exception as e:
    logging.error(f"An error occurred: {e}")
        

Understanding the Exception Hierarchy

To understand the hierarchy of exceptions and which ones to catch, it’s useful to know how exceptions are structured in Python. As mentioned earlier, BaseException is at the top, and most exceptions inherit from Exception. Here’s a visual representation:

BaseException
    ├── SystemExit
    ├── KeyboardInterrupt
    ├── GeneratorExit
    └── Exception
        ├── ArithmeticError
        ├── AssertionError
        ├── AttributeError
        ├── BufferError
        ├── EOFError
        ├── ImportError
        ├── LookupError
        ├── MemoryError
        ├── NameError
        ├── OSError
        ├── ReferenceError
        ├── RuntimeError
        ├── StopIteration
        ├── SyntaxError
        ├── SystemError
        ├── TypeError
        ├── ValueError
        └── Warning
        

Understanding this hierarchy can help you decide which exceptions to catch and how to handle them appropriately.

Conclusion

While except Exception as e is a valid construct in Python, using it indiscriminately can lead to poor error handling and hidden bugs. By being specific about the exceptions you catch and using best practices, you can write more robust and maintainable code. Remember, good exception handling is not just about catching errors; it’s about handling them in a way that makes your code more resilient and easier to understand.

要查看或添加评论,请登录

社区洞察

其他会员也浏览了