What Is Wrong With Using a Bare 'Except'

What is wrong with using a bare 'except'?

Bare except will catch exceptions you almost certainly don't want to catch, including KeyboardInterrupt (the user hitting Ctrl+C) and Python-raised errors like SystemExit

If you don't have a specific exception you're expecting, at least except Exception, which is the base type for all "Regular" exceptions.


That being said: you use except blocks to recover from known failure states. An unknown failure state is usually irrecoverable, and it is proper behavior to fatally exit in those states, which is what the Python interpreter does naturally with an uncaught exception.

Catch everything you know how to handle, and let the rest propagate up the call stack to see if something else can handle it. In this case the error you're expecting (per the docs) is pyautogui.ImageNotFoundException

Should I always specify an exception type in `except` statements?

It's almost always better to specify an explicit exception type. If you use a naked except: clause, you might end up catching exceptions other than the ones you expect to catch - this can hide bugs or make it harder to debug programs when they aren't doing what you expect.

For example, if you're inserting a row into a database, you might want to catch an exception that indicates that the row already exists, so you can do an update.

try:
insert(connection, data)
except:
update(connection, data)

If you specify a bare except:, you would also catch a socket error indicating that the database server has fallen over. It's best to only catch exceptions that you know how to handle - it's often better for the program to fail at the point of the exception than to continue but behave in weird unexpected ways.

One case where you might want to use a bare except: is at the top-level of a program you need to always be running, like a network server. But then, you need to be very careful to log the exceptions, otherwise it'll be impossible to work out what's going wrong. Basically, there should only be at most one place in a program that does this.

A corollary to all of this is that your code should never do raise Exception('some message') because it forces client code to use except: (or except Exception: which is almost as bad). You should define an exception specific to the problem you want to signal (maybe inheriting from some built-in exception subclass like ValueError or TypeError). Or you should raise a specific built-in exception. This enables users of your code to be careful in catching just the exceptions they want to handle.

Any Reason why Bare-Except's are Frowned Upon

Your example is a wonderful example of why this is a bad idea. Your program is not "if the data is nonexistent or corrupt, overwrite it with a template". Your program is "if anything at all goes wrong, try to overwrite the data with a template".

For example, if you had a typo in the code that gets executed while trying to load the data, your program will not inform you, and instead overwrite all of your (valid!) data with the template. This could be a rather disastrous bug, both in terms of lost data, and how easily you can convince yourself that this couldn't possibly be the problem, should the typo occur in an infrequently exercised code path that your test cases miss.

Another example of things going wrong is if the user decided to try and abort the program with Ctrl+C. You'd catch the KeyboardInterrupt and promptly clobber all of his data.

can every bare 'except' be converted to something better?

If you just use except then you catch everything that inherits from BaseException, including things like KeyboardInterrupt. This is probably not what you intend. Chances are good that you will end up masking error conditions that you actually wanted to know about.

This page discusses a potentially good use of catching all exceptions - to log the exception (e.g. at the top level of a program or module) and immediately re-raise it. That bit about re-raising it is important because it means you're not hiding the error when you shouldn't.

Why is Python raising exception, despite a bare Except block?

Figured it.

This is what is going on:

1) The main query raise an error.

2) It is handled.

3) As the query is inside a context manager, the context manager exites it's object, e.g. connection instance.

4) As the MySQL server has gone away, the __exit__ method of the connection class can not execute properly.

5) As it can not execute properly, it raises an error within the scope of the context manager, outside the scope of the bare handling exception inside query.

You can get the same result if you experiment with the following code:

class ContextManagerException(Exception):
pass


class TryBlockException(Exception):
pass


class A(object):
def __enter__(self):
return self

def __exit__(self, exc_type, exc_value, tb):
raise ContextManagerException


with A() as a:
try:
raise TryBlockException
pass
except Exception as e:
print(e)

As you can see, the risen exception is indeed risen from the context manager, and indeed it is risen from the print(e) line, as it is the last line to execute from the context manager.

How to prevent too broad exception in this case?

The PEP8 guide you quote suggests that it is okay to use a bare exception in your case provided you are logging the errors. I would think that you should cover as many exceptions as you can/know how to deal with and then log the rest and pass, e.g.

import logging

list_of_functions = [f_a,f_b,f_c]
for current_function in list_of_functions:
try:
current_function()
except KnownException:
raise
except Exception as e:
logging.exception(e)

Difference between except: and except Exception as e:

In the second you can access the attributes of the exception object:

>>> def catch():
... try:
... asd()
... except Exception as e:
... print e.message, e.args
...
>>> catch()
global name 'asd' is not defined ("global name 'asd' is not defined",)

But it doesn't catch BaseException or the system-exiting exceptions SystemExit, KeyboardInterrupt and GeneratorExit:

>>> def catch():
... try:
... raise BaseException()
... except Exception as e:
... print e.message, e.args
...
>>> catch()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 3, in catch
BaseException

Which a bare except does:

>>> def catch():
... try:
... raise BaseException()
... except:
... pass
...
>>> catch()
>>>

See the Built-in Exceptions section of the docs and the Errors and Exceptions section of the tutorial for more info.



Related Topics



Leave a reply



Submit