PEP 572: Address several small issues (#709)
- Dropped "TODO: Include Guido's evidence, and do a more systematic search." I think the current text is good enough. - Relented on assignment expressions in default values other than top level. (Mainly because the syntactic/semantic check would be awkward, and it was already called out as a possible style recommendation instead.) - Clarified that a lambda counts as "the current scope" (containing an assignment expression). - Added prohibition on [... for i in i := ...]. - Specified that scope-related prohibitions should raise TargetScopeError, a subclass of SyntaxError.
This commit is contained in:
parent
3e128e568b
commit
a9b8753635
44
pep-0572.rst
44
pep-0572.rst
|
@ -111,8 +111,6 @@ efficient rewrite would have been::
|
|||
if match2:
|
||||
return match2.group(2)
|
||||
|
||||
(TODO: Include Guido's evidence, and do a more systematic search.)
|
||||
|
||||
|
||||
Syntax and semantics
|
||||
====================
|
||||
|
@ -144,50 +142,45 @@ There are a few places where assignment expressions are not allowed,
|
|||
in order to avoid ambiguities or user confusion:
|
||||
|
||||
- Unparenthesized assignment expressions are prohibited at the top
|
||||
level of an expression statement; for example, this is not allowed::
|
||||
level of an expression statement. Example::
|
||||
|
||||
y := f(x) # INVALID
|
||||
(y := f(x)) # Valid, though not recommended
|
||||
|
||||
This rule is included to simplify the choice for the user between an
|
||||
assignment statements and an assignment expression -- there is no
|
||||
syntactic position where both are valid.
|
||||
|
||||
- Unparenthesized assignment expressions are prohibited at the top
|
||||
level in the right hand side of an assignment statement; for
|
||||
example, the following is not allowed::
|
||||
level of the right hand side of an assignment statement. Example::
|
||||
|
||||
y0 = y1 := f(x) # INVALID
|
||||
y0 = (y1 := f(x)) # Valid, though discouraged
|
||||
|
||||
Again, this rule is included to avoid two visually similar ways of
|
||||
saying the same thing.
|
||||
|
||||
- Unparenthesized assignment expressions are prohibited for the value
|
||||
of a keyword argument in a call; for example, this is disallowed::
|
||||
of a keyword argument in a call. Example::
|
||||
|
||||
foo(x = y := f(x)) # INVALID
|
||||
foo(x=(y := f(x))) # Valid, though probably confusing
|
||||
|
||||
This rule is included to disallow excessively confusing code, and
|
||||
because parsing keyword arguments is complex enough already.
|
||||
|
||||
- Assignment expressions (even parenthesized or occurring inside other
|
||||
constructs) are prohibited in function default values. For example,
|
||||
the following examples are all invalid, even though the expressions
|
||||
for the default values are valid in other contexts::
|
||||
- Unparenthesized assignment expressions are prohibited at the top
|
||||
level of a function default value. Example::
|
||||
|
||||
def foo(answer = p := 42): # INVALID
|
||||
...
|
||||
|
||||
def bar(answer = (p := 42)): # INVALID
|
||||
def foo(answer=(p := 42)): # Valid, though not great style
|
||||
...
|
||||
|
||||
def baz(callback = (lambda arg: p := arg)): # INVALID
|
||||
...
|
||||
|
||||
This rule is included to avoid side effects in a position whose
|
||||
This rule is included to discourage side effects in a position whose
|
||||
exact semantics are already confusing to many users (cf. the common
|
||||
style recommendation against mutable default values). (TODO: Maybe
|
||||
this should just be a style recommendation except for the
|
||||
prohibition at the top level?)
|
||||
style recommendation against mutable default values), and also to
|
||||
echo the similar prohibition in calls (the previous bullet).
|
||||
|
||||
Scope of the target
|
||||
-------------------
|
||||
|
@ -196,7 +189,8 @@ An assignment expression does not introduce a new scope. In most
|
|||
cases the scope in which the target will be bound is self-explanatory:
|
||||
it is the current scope. If this scope contains a ``nonlocal`` or
|
||||
``global`` declaration for the target, the assignment expression
|
||||
honors that.
|
||||
honors that. A lambda (being an explicit, if anonymous, function
|
||||
definition) counts as a scope for this purpose.
|
||||
|
||||
There is one special case: an assignment expression occurring in a
|
||||
list, set or dict comprehension or in a generator expression (below
|
||||
|
@ -231,12 +225,11 @@ comprehension, for example::
|
|||
|
||||
An exception to this special case applies when the target name is the
|
||||
same as a loop control variable for a comprehension containing it.
|
||||
This is invalid. (This exception exists to rule out edge cases of the
|
||||
This is invalid. This exception exists to rule out edge cases of the
|
||||
above scope rules as illustrated by ``[i := i+1 for i in range(5)]``
|
||||
or ``[[(j := j) for i in range(5)] for j in range(5)]``. Note that
|
||||
this exception also applies to ``[i := 0 for i, j in stuff]``.)
|
||||
|
||||
TODO: prohibit [... for i in i := ...]
|
||||
this exception also applies to ``[i := 0 for i, j in stuff]``, as well
|
||||
as to cases like ``[i+1 for i in i := stuff]``.
|
||||
|
||||
A further exception applies when an assignment expression occurrs in a
|
||||
comprehension whose containing scope is a class scope. If the rules
|
||||
|
@ -254,7 +247,8 @@ variable defined in the class scope from a comprehension.)
|
|||
See Appendix B for some examples of how the rules for targets in
|
||||
comprehensions translate to equivalent code.
|
||||
|
||||
TODO: use a a subclass of SyntaxError for various prohibitions?
|
||||
The two invalid cases listed above raise ``TargetScopeError``, a
|
||||
subclass of ``SyntaxError`` (with the same signature).
|
||||
|
||||
Relative precedence of ``:=``
|
||||
-----------------------------
|
||||
|
|
Loading…
Reference in New Issue