try..except with empty exceptions

Chris Angelico rosuav at gmail.com
Sun Apr 12 03:00:18 EDT 2015


On Sun, Apr 12, 2015 at 4:33 PM, Cameron Simpson <cs at zip.com.au> wrote:
> On 12Apr2015 09:21, Chris Angelico <rosuav at gmail.com> wrote:
>> Fair enough. Do you know how often you actually catch stuff that
>> wouldn't be caught by "except BaseException:"?
>
>
> I don't know and I'm not sure I care (but discussion below). I would need to
> examine carefully what they were. Looking at the 2.7.9 doco for Exception it
> almost looks like that is what I should often want. (Though I think I have
> some circumstances where I might prefer BaseException.)

A very good reason to avoid "except:" and always put some name in
there. Forces you to think about which of the two you want.

>> You could simply mandate that, from version X.Y of your Asynchron
>> module onward, old-style classes must not be thrown.
>
> Except that Asynchron, like several of the other circumstances, is expected
> to be used with arbitrary callables from outside sources.

Yes, but you have version requirements already. You can't expect
someone to deploy Asynchron on Python 2.1, I would guess. In the same
way, you can simply state that raising what Steven referred to as an
NBEE will cause problems.

>> What you're looking at here is exactly why it's not spelled that way.
>> The normal thing to do is NOT to catch absolutely everything, but to
>> allow KeyboardInterrupt and SystemExit to continue to bubble up.
>> That's spelled "except Exception".
>
>
> Yes. But can I guarrentee that those are the only two? The 2.7.9 doco says:
>
>   exception Exception
>       All built-in, non-system-exiting exceptions are derived from this
> class.
>
> I suppose I could consider that clear, but certainly in case of
> KeyboardInterrupt I might want to involve cleanup actions. I'll ignore
> interactive situations; messy.

That's what try/finally is for. You can do your cleanup without caring
exactly what was raised.

> Yes. But it seems to me that "normal use" generally means the situation
> where one catches a quite narrow set of exceptions for which particular
> recoveries are well defined.

That is, in fact, the most normal way to catch exceptions. What you're
doing here is a distinctly abnormal situation: creating a protective
boundary between two separate layers.

> However, when I want "all exceptions", that really is what I mean. I need to
> think quite carefully about KeyboardInterrupt and SystemExit. The former is
> guarrenteed to be delivered to the main thread IIRC and I'd want to catch
> that specificly in my main() function, if at all. And I suspect that
> SystemExit really shouldn't be stopped; if something untoward is calling it,
> should it not succeed? Or be exposed and then hunted down and killed!

That's what you have to decide, yeah. Chances are you just want to
catch Exception in a lot of the cases.

> However, my Asynchron class really is a little special. I use Asynchron to
> underpin a bunch of classes whose instances get fulfilled later, especially
> callables that get queued and run at a suitable time (or which get run in
> response to some external long awaited event). ...
> Anyway, at some point in the above example "function" gets called (by the
> infrastructure of "Later") with the supplied arguments as the Later
> processes its queue.
>
> So in this situation: should I catch and defer KeyboardInterrupt or
> SystemExit?  Maybe not, but the clean/naive implementation says to catch
> absolutely everything.

That is a tough one. I would support either of BaseException and
Exception for this case, and whichever you pick, there will be a time
when you wish you'd picked the other. But at least now you get a
chance to think about it.

> Finally, if we were to expunge support for "except:", one would also need a
> cast iron guarrentee that no exception could possibly occur which was not a
> subclass of BaseException. I'd expect that to mean that "raise" of a
> non-instance of BaseException to itself raise a TypeError.

As of Py3, that is indeed the case. In Py2, you can at least run
"python -3" and get a DeprecatoinWarning any time you attempt to raise
a NBEE; I don't know if you can make that into an error. But even if
you can't, all you have to do is explain that it's equivalent to any
other form of shooting yourself in the foot.

ChrisA



More information about the Python-list mailing list