[Python-ideas] except expression

Chris Angelico rosuav at gmail.com
Sun Feb 16 22:52:41 CET 2014


On Mon, Feb 17, 2014 at 1:37 AM, Nick Coghlan <ncoghlan at gmail.com> wrote:
> Thanks for putting this together, Chris! :)

Thanks for the edit advice!

> This section (or a separate "Detailed Semantics" one) is missing a
> detailed specification of the semantics, in particular:

> - what happens if an except expression is used as part of the except
> clause in an ordinary try statement, or another except expression?

That should be fairly obvious - it's like nesting try/except. Does it
need to be said?

> - what scope are subexpressions evaluated in?
> - if the "as" clause is permitted, what is the scope of that name binding?
> - if the current scope, then how does that square with the changes to
> list comprehensions in 3.0 to always use a new scope for the iteration
> variables (the same as generator expressions). Keep in mind that the
> except expression will need to preserve the Python 3 except clause
> behaviour of unbinding the exception name after evaluating the
> subexpression
> - if a new scope, what impact does that have on what subexpressions
> are valid, especially at class scope?
>
> (I suspect defining these except expressions as creating a new
> transient scope, akin to comprehensions and generator expressions,
> will actually avoid a variety of issues, in particular, preventing
> leaking the name of the bound exception into the containing scope. I
> also suspect a transient scope would make the PEP's currently
> preferred colon based notation more palatable to some readers)

Yeah, now, this part is a problem. Subsequently to the version posted,
I've added an Open Issues subsection regarding scope.

"""
Scope of default expressions and 'as'
-------------------------------------

In a try/except block, the use of 'as' to capture the exception object creates
a local name binding, and implicitly deletes that binding in a finally clause.
As 'finally' is not a part of this proposal (see below), this makes it tricky
to describe; also, this use of 'as' gives a way to create a name binding in an
expression context. Should the default clause have an inner scope in which the
name exists, shadowing anything of the same name elsewhere? Should it behave
the same way the statement try/except does, and unbind the name? Should it
bind the name and leave it bound? (Almost certainly not; this behaviour was
changed in Python 3 for good reason.)
"""

It's a knotty problem. I'm currently inclined to the inner scope idea
(like a comprehension), but that's inconsistent with the statement
form of try/except. Is that difference going to confuse people?

>>> e = 1234
>>> [e for e in (1,)]
[1]
>>> e
1234
>>> try:
    1/0
except ZeroDivisionError as e:
    pass
>>> e
Traceback (most recent call last):
  File "<pyshell#147>", line 1, in <module>
    e
NameError: name 'e' is not defined

Also, what are the implications on the inside? Disassembling a
function with a list comp shows that it calls an inner function, which
I presume is the only way CPython can create an inner scope. Does the
default-expression then have to be a separate function, and if so,
what does that mean?

Alternatively, what would it be like if an expression could do a name
binding and unbinding (consistently with the statement form)? Would
that confuse people no end?

ChrisA


More information about the Python-ideas mailing list