try..except with empty exceptions

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sun Apr 12 06:05:38 CEST 2015


On Sun, 12 Apr 2015 07:37 am, Cameron Simpson wrote:

> On 11Apr2015 21:21, Chris Angelico <rosuav at gmail.com> wrote:
>>But I agree, it would be very nice if Python 3 could have abolished
>>the truly confusing part of this, where "except:" catches everything.
>>Forcing people to spell it "except BaseException:" would fix all of
>>this. How hard is it to deprecate and then remove that, same as string
>>exceptions were removed?
> 
> I guess I'll go over there to oppose it then.
> 
> Why? It makes it harder to write portable python 2/3 code and does not add
> any semantic advantage.

I don't think it does make it harder to write hybrid 2+3 applications.

The thing is, in 3, you *must* inherit from BaseException. String exceptions
are gone (they were removed in 2.6, so if you're still using them, you code
won't even run in 2.6 or 2.7). Old-style classes are gone, so your classic
exceptions will automatically be promoted to new-style classes.

class MyException:
    pass

In 2.x code, that can be raised and caught. But not in 3.x, so if you are
writing hybrid code you have to change that anyway! It's surely a trivial
change:

class MyException(Exception):
    pass


Now you can raise it in both 2.x and 3.x, and you can catch it with "except
Exception", as recommended.

Now, *technically* there are things that are possible with classic classes
in 2.x which are hard or impossible once you inherit from Exception, but
(1) I don't imagine that exceptions will use them, and (2) you still have
to deal with that when migrating anyway, so you are no worse off.

[To be precise, I'm referring to things like the ability to override dunder
methods on a per-instance basis. Want to give this specific instance, and
no other, the ability to support + addition? You can with classic classes,
but not easily with new-style classes. But who is going to want to do that
for an exception?]



> Unless there's a common root exception class in Python 2, which I believe
> there isn't, you can't catch all exceptions in python 2 without the
> "except:" syntax. 

Correct.


> Which means the _only_ way to have some code in both 2 
> and 3 that does it requires 2 codebases.

You would think so, but not really. The thing is, if you want to use a
single codebase, you cannot *raise* strings, or classic classes that don't
inherit from BaseException, not even in your 2.x code. Since you aren't
raising them, there's no need to catch them!

In hybrid code running under 2.x, a non-BaseException exception (NBEE) is a
bug to be fixed. The fact that you are no longer catching it in 2.x is a
good thing, because that forces you to find the offending code which raises
the NBEE and fix it.


 
> As one who tries to have his code run in both 2 (usually recent 2, like
> 2.6/2.7) and 3, this change would cause a signification breakage for me
> without bringing any semantic benefits.

I think that the only way that would be true is if you are referring to a
*library*, rather than an application. In other words, you have:

- a single code base with hybrid 2+3 code;

- your users are integrating it with other people's code (perhaps their own)
  which you do not control, i.e. it is a library, not an application;

- that 3rd party code raises string exceptions (up to 2.5) or classic NBEE;

- you have to catch those exceptions, and cannot just say to your users "we
  don't support non-BaseException exceptions any more".

Life is tough for library authors who want to support old code :-(


The solution, as I see it, would be to extract only the bits of your code
that does the exception handling, and split it into two separate files:

# catcher2.py
from common import dostuff
try: 
    ...
except BaseException:
    dostuff()
except:
    warnings.warn("fix your code, you neanderthal!")
    dostuff()

# catcher3.py
from common import dostuff
try:
    ...
except BaseException:
    dostuff()


and then conditionally import one or the other. Alternatively, you can use
exec, and a single file.

I wouldn't say that either solution thrills me. If I were in that position,
I would simply document that string exceptions and classic-class exceptions
are no longer supported, and make my users responsible for fixing or
replacing the third-party code that raises such things.



> Without vigorous use of the time machine I don't see a fix here.
> 
> For the record, I would be ok (but not "for") never having had bare
> "except" if all exceptions had always had a common root.
> 
> Hmm. Can I catch "object"? Sounds awful, but might work.

No.

http://bugs.python.org/issue2291

See also PEP 352, which explains some of the motivation of the post 2.4
changes to exceptions, and the expected timeline for changes leading up to
3.x. (Some of the PEP is a bit obsolete, it still refers to Python 2.9
being the last of the 2.x series.)

http://www.python.org/dev/peps/pep-0352/



-- 
Steven




More information about the Python-list mailing list