[Python-ideas] Improving Catching Exceptions

Nick Coghlan ncoghlan at gmail.com
Sat Jun 24 09:45:25 EDT 2017


On 24 June 2017 at 22:31, Greg Ewing <greg.ewing at canterbury.ac.nz> wrote:
> Steven D'Aprano wrote:
>> I think we're over-generalizing this problem. There's two actual issues
>> here, and we shouldn't conflate them as the same problem:
>>
>> (1) People write buggy code based on invalid assumptions of what can and
>> can't raise. E.g.:
>>
>> (2) There's a *specific* problem with property where a bug in your getter
>> or setter that raises AttributeError will be masked, appearing as if the
>> property itself doesn't exist.
>
> Agreed.
>
> Case 1 can usually be handled by rewriting the code so as to
> make the scope of exception catching as narrow as possible.
>
> Case 2 needs to be addressed within the method concerned on a
> case-by-case basis. If there's a general principle there, it's
> something like this: If you're writing a method that uses
> an exception as part of it's protocol, you should catch any
> incidental occurrences of the same exception and reraise it
> as a different exception.
>
> I don't think there's anything more the Python language could do
> to help with either of those.

While I used to think that, I'm no longer sure it's true, as it seems
to me that a `contextlib.convert_exception` context manager could help
with both of them. (That's technically the standard library helping,
rather than the language per se, but it's still taking a currently
obscure implementation pattern and making it more obvious by giving it
a name)

So if we assume that existed, and converted the given exception to
RuntimeError (the same way PEP 479 does for StopIteration), we'd be
able to write magic methods and properties in the following style:

   def __getitem__(self, n):
      self.validate(n)
      with contextlib.convert_exception(IndexError):
          # If we get an IndexError in here, it's a bug
          return self._getitem(n)

That idiom then works the same way regardless of how far away your
code is from the exception handler you're trying to bypass - you could
just as easily put it inside the `self._getitem(n)` helper method
instead.

Cheers,
Nick.

-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia


More information about the Python-ideas mailing list