[Python-ideas] except expression

Andrew Barnert abarnert at yahoo.com
Tue Feb 18 23:02:29 CET 2014


From: Chris Angelico <rosuav at gmail.com>

Sent: Tuesday, February 18, 2014 12:55 PM


> Alright, results are in.
> 
> Script:
> https://github.com/Rosuav/ExceptExpr/blob/master/find_except_expr.py
> Output:
> https://github.com/Rosuav/ExceptExpr/blob/master/candidates.txt
> Annotated examples:
> https://github.com/Rosuav/ExceptExpr/blob/master/examples.py
> 
> The last one is the most readable. I've collected up a bunch of viable
> candidates for translation. (Note that I'm not advocating going
> through and editing these files for no other reason. That'd just be
> code churn. But these are cases where, had this feature existed when
> that code was written, it could have been taken advantage of.)

It's interesting that some of these call functions that have a fallback-value parameter, so it may be worth asking why they weren't already written as expressions, and whether the new exception expression would be better.

Taking one example at random:

# Lib/pdb.py:433:
        try:
            func = getattr(self, 'do_' + cmd)
        except AttributeError:
            func = self.default

    func = getattr(self, 'do_' + cmd, self.default)

    func = getattr(self, 'do_' + cmd) except AttributeError: self.default

These aren't identical: using the existing default parameter to getattr would require accessing self.default. Is that guaranteed to exist? (And to be relatively cheap to access?) If so, then presumably there's some reason for the more explicit form, and I don't think the except-expression version would be acceptable if the three-argument version isn't.

But if not, I think that's a clear win for this proposal: Here's something we would have liked to write as an expression, but, even with a function that already has a default parameter, we couldn't do so without the except-expression.

There are even more cases like this:

# Lib/sysconfig.py:529:
        try:
            _CONFIG_VARS['abiflags'] = sys.abiflags
        except AttributeError:
            # sys.abiflags may not be defined on all platforms.
            _CONFIG_VARS['abiflags'] = ''

… while you _could_ replace this with getattr(sys, 'abiflags', ''), only a madman would do so… but in a language with ".?"-type syntax you'd almost certainly use that, and with this proposal, sys.abiflags except AttributeError: '' is equivalent and much more readable. So, that looks like another win.

> My script is currently _very_ simplistic. It looks *only* for

> assignments, so it won't find something like this:
> 
> try:
>     foo.append(args[0])
> except IndexError:
>     foo.append('')
> 
> which is correct, because it's impossible to know whether foo.append()
> will raise IndexError. (Chances are it won't, especially if we know
> foo is a list, for instance.) It's not safe to directly translate that
> sort of thing. It might, however, be something worth improving, as it
> narrows the scope of the except clause. But if that same code is
> written thus:
> 
> try:
>     tmp = args[0]
> except IndexError:
>     tmp = ''
> foo.append(tmp)
> 
> then the script _will_ find it, and then it really is a candidate for editing.
> 
> Point to note: Apart from one instance, where it wasn't being used
> anyway, I found not a single instance of 'as' being used. There was
> one case where sys.exc_info() was referenced, though, so this may just
> mean that the stdlib files in question are maintaining compatibility
> with old versions of Python.
> 
> I didn't look at most of the tests. The script found 195 plausible
> try/except blocks, of which 37 have the word "test" in the name;that
> leaves 158 that are likely to benefit from this change. There are a
> couple of false positives, but not many.
> 
> Next is to figure out what else is a candidate for editing. Here's my
> current criteria, straight from the docstring:
> 
> """Report on 'simple' try/except statements.
> 
> The definition of simple is:
> 1. No else or finally clause
> 2. Only one except clause (currently)
> 3. Exactly one statement in the try clause
> 4. Exactly one statement in each except clause
> 5. Each of those statements is the same type.
> 6. That type is one that could be an expression.
> 7. Those statements are all compatible.
> 
> The last two are the trickiest. Currently I'm looking
> only for assignments, where both try and except assign
> to the same target. This is, however, too narrow."""
> 
> Interestingly, removing criterion 2 gives us three additional examples
> out of the test suite, and nothing else. There are no cases outside of
> the test suite that look like this:
> 
> try:
>     x = some_calculation
> except ValueError:
>     x = something_else
> except OverflowError:
>     x = different_thing
> 
> (The test suite has one case with those exact two exceptions, and a
> pair that use OverflowError and ZeroDivisionError. In each case,
> they're comparing two actions to make sure they give the same result,
> where "throwing OverflowError" is a result like any other.)
> 
> Conclusions: The need for chained exception catching might not be so
> great after all, and even the 'as' keyword isn't as (heh heh)
> important as I thought it was.
> 
> Alternate conclusion: My sample is too small. Need more. Data, you
> have the helm.
> 
> ChrisA
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
> 


More information about the Python-ideas mailing list