[Python-ideas] Use `isinstance` check during exception handling

sjoerdjob at sjec.nl sjoerdjob at sjec.nl
Thu Nov 5 01:00:12 EST 2015


> On 11/4/2015 5:02 PM, sjoerdjob at sjec.nl wrote:
>> TL;DR: Change exception checking logic  from
>>      err.__class__ in exc.__mro__
>
> This is backwards. err.__class__ must be a (true) subclass, not a
> superclass, of exc, where err = exception instance, exc = exception class.

Ah, a minor glitch when writing the e-mail. My apologies. It should be
    exc in err.__class__.__mro__

> There are two checks in the exception process.  First, for 'raise err',
> is that err is a instance of StopIteration, which is to say,
> err.__class__ is a subclass of StopIteration.  To avoid the fakery of
> __instancecheck__ and __subclasscheck__, I presume this is implemented
> as something like one of
>    StopIteration in err.__class__.__mro__
>    StopIteration in type(err).__mro__
> (There was a recent pydev discussion about when and why these may
> diverge.)

I can't actually find the logic which handles the `StopIteration`,
unless you are talking specifically about the exception handling in
for-loops and everything else that relates to iterables. (The code I'm
looking at is Python/errors.c:PyErr_GivenExceptionMatches).

> The second, for 'except exc', is that exc is a superclass (other than
> object) of type(err).  I presume this is implemented as something like
>    exc in type(err)[:-1]  # exclude object class
> This assume that err has already passed the first check above.

>From what I can find (again: errors.c), the current logic is:

  (note: `err` is what is raised, `exc` is what's matched against)
  * if `exc` is a tuple, recurse over the elements of the tuple.
  * if the `err` is an instance, replace it with its class
  * if both `err` and `exc` are subclasses of exception:
        check PyType_IsSubtype(err, exc)
    which basically is the same as (see Objects/typeobject.c)
        exc in err.__mro__
    note: not err.__mro__[:-1].

> The `try` doc says "An object is compatible with an exception if it is
> the class or a base class of the exception object".  This text fails to
> exclude the object class as a compatible object.  CPython code rejects
> 'except object:' with "TypeError: catching classes that do not inherit
> from BaseException is not allowed"
>
>> to
>>      isinstance(err, exc)
>> Because it is more powerful,
>
> ?? This predicate is True more often than the current one because it a)
> does not exclude exc = object

My idea was basically to still demand that both `err` and `exc` must
sub-class `BaseException`, but that only the check for
`PyType_IsSubtype` would be replaced with `PyObject_IsInstance`.

>  >>> isinstance(Exception(), object)
> True
>
> and b) accesses exc.__instancecheck__ (which is part of your point).
> This makes it a weaker predicate.

Yes, the predicate is weaker. And that gives us more power.

> I don't have strong opinions at the moment about the proposal itself,
> but semantic changes in core python syntax need a PEP (once you think
> there is *some* support).

It's not a syntax-change, but a semantics-change. Still I would not be
surprised if it indeed does need a PEP, but there will only be a point
in doing that when there is *some* support. Before writing that PEP, I
was checking here to see if I could find some support, or if it the pros
don't outweigh the cons for the 'masses'.

> --
> Terry Jan Reedy

Regards,
Sjoerd Job Postmus


More information about the Python-ideas mailing list