Deprecate bare except

In the last few versions pyflakes has warned about bare excepts:

try:
    ...
except:
    ...

which have the unpleasant side effect of catching KeyboardInterrupt and SystemExit. I have previously taken the view that it’s basically OK if the except block contains a bare raise:

try:
    ...
except:
    ...
    raise

… but in practice beginners make mistakes with this all the time. You can always very conveniently write

except Exception:

or even

except BaseException:

the latter offering very little possibility that beginners will use it by mistake. So I came round to the idea that “explicit is better than implicit”.

Could the bare except syntax be officially deprecated, eg. behind a __future__?

>>> from __future__ import bare_except
>>> try:
...    ...
... except: 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
SyntaxError: except statement must have an exception type expression
>>> bare_except
_Feature((3, 9, 0, 'alpha', 1), (3, 11, 0, 'alpha', 0), ...)
2 Likes

Possibly. It was brought up during the Python 3 transition but was deemed to disruptive to follow through with. Personally I would love to make bare except statements illegal and then after a proper amount of time bring them back to mean except Exception.

1 Like

It is handy for the “do something and reraise” condition. E.g. you want to abort a transaction no matter what exception occurred. It probably wouldn’t be easy, but raising an exception if a bare except clause didn’t call bare raise would be useful.

You would still be able catch any exception; that’s just except BaseException. It’s already TypeError to raise anything that doesn’t derive from BaseException.

1 Like

Maybe it would have been, but actually it’s something 2to3 would have been able to fix pretty reliably by rewriting to except BaseException.

There was also disagreement over what a bare except should mean. Regardless, it’s not worth arguing about since we’re kind of done with worrying about what features to put into Python 3.0. :wind_face:

2 Likes

I might be convinced to support deprecating and removing bare except clauses: they’re a real problem and I see them often in many code-bases. But I’d be highly against bringing them back later with a new meaning.

1 Like

If followed by “raise” bare except has a legitimate use case which is not so rare to encounter. If removed, how should the new code be ported in order to mean exactly the same thing as “except:”?

1 Like

except BaseException: already means the same so I’m not sure what you’re after beyond that.

1 Like

What advantage does except BaseException provide over a bare except? Meaning, if we were to deprecate the latter, is there any real improvement to code quality or readability?

3 Likes

For me the only advantage is that bare except, being much shorter to type, is an attractive nuisance to people who are not experienced Python programmers.

3 Likes

I agree with @pitrou. Writing except BaseException: proves that the person who wrote that actively thought about which exception class to use. It’s not something that you write by mistake.

Precisely because except: is so simple, it is regularly misused by people that don’t really understand what it means or are simply lazy.

Python seems to be chosen by none-fulltime-programmers (scientists, mathematicians, financial, sysadmins, … ) for the more flexible programming and no need to know underlying programming logics unless you really want/need. ‘Just catch any exception while figuring out the code for the function.’ or ‘Just drop the anomalies but keep on treating the rest of the data’. I understand it’s no good practice, but it’s easy and well readable if you want to spend more precious time on working with the partial data/results instead of figuring out all coding obligations.

I understand that ‘except:’ now means ‘except BaseException:’, but ideally should have been ‘except Exception’? First deprecate to not use ‘except:’ and bring back is confusing. What would be the impact just changing it one version to another? SystemExit, KeyboardInterrupt and GeneratorExit will not be caught. Those are deliberate actions to stop the script/program anyway?

It would avoid a lot of kill $(ps aux | grep python-project | awk '{print $2}') actions. Now understanding the reason, I don’t know if I will start writing ‘except Exception:’ everywhere? Next kill pid situation will raise my attention to this anyhow. Thanks, interesting. “exception hierarchy” helped understanding the situation.

1 Like

It would break a lot of existing code, especially KeyboardInterrupt. I have no concrete data points (maybe it’s worthwhile to look into this), but anecdotally it is common to use this to perform some final cleanup when user interrupts your program. Changing bare except without deprecation would make those cleanups not run, leading to subtle bugs not immediately apparent.

Do any linters warn on bare except? That could be a start without having to change the language. PEP 8 could also be updated to recommend never to use bare except.

  • pycodestyle (and inheritantly flake8) lints it by default (against heated objections).
  • PyLint has W0702 (not sure if it’s on by default; I think so?)
  • Black does not change a bare except (maybe this is a good place to start, given its “officially recommended” status?)
1 Like

What would it change it into?

  • If Exception then this changes the functionality, which is something black must not do IMHO.
  • If BaseException then any incorrectly used bare excepts are now much less obvious, and pycodestyle and pylint will stop warning about them.
1 Like

Understood. So using bare except for any exception to do some final cleanup, because user knew that also deliberate interrupts (keyboard/system/kill/…) were caught by bare except. Then indeed would cause some backward compatibility issues.

1 Like

My original thought went to BaseException (ruling out Exception with the same reason as yours), but you got a good point here. I guess Black, being a code formatter, is not a suitable tool to make such a logical correction.

This definitely feels more like the responsibility of linters than Python itself.

1 Like