In most contexts where arbitrary Python expressions can be used, a named expression can appear. This is of the form NAME := expr where expr is any valid Python expression other than an unparenthesized tuple, and NAME is an identifier.

The value of such a named expression is the same as the incorporated expression, with the additional side-effect that the target is assigned that value:

This shows that what looks like an assignment operator in an f-string is not always an assignment operator. The f-string parser uses : to indicate formatting options. To preserve backwards compatibility, assignment operator usage inside of f-strings must be parenthesized. As noted above, this usage of the assignment operator is not recommended.

This allows lambda to always bind less tightly than := ; having a name binding at the top level inside a lambda function is unlikely to be of value, as there is no way to make use of it. In cases where the name will be used more than once, the expression is likely to need parenthesizing anyway, so this prohibition will rarely affect code.

The reasoning here is similar to the two previous cases; this ungrouped assortment of symbols and operators composed of : and = is hard to read correctly.

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), and also to echo the similar prohibition in calls (the previous bullet).

This rule is included to disallow excessively confusing code, and because parsing keyword arguments is complex enough already.

Again, this rule is included to avoid two visually similar ways of saying the same thing.

Unparenthesized assignment expressions are prohibited at the top level of the right hand side of an assignment statement. Example:

This rule is included to simplify the choice for the user between an assignment statement and an assignment expression -- there is no syntactic position where both are valid.

There are a few places where assignment expressions are not allowed, in order to avoid ambiguities or user confusion:

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. 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 collectively referred to as "comprehensions") binds the target in the containing scope, honoring a nonlocal or global declaration for the target in that scope, if one exists. For the purpose of this rule the containing scope of a nested comprehension is the scope that contains the outermost comprehension. A lambda counts as a containing scope.

The motivation for this special case is twofold. First, it allows us to conveniently capture a "witness" for an any() expression, or a counterexample for all() , for example:

if any((comment := line).startswith('#') for line in lines): print("First comment:", comment) else: print("There are no comments") if all((nonblank := line).strip() == '' for line in lines): print("All lines are blank") else: print("First non-blank line:", nonblank)

Second, it allows a compact way of updating mutable state from a comprehension, for example:

# Compute partial sums in a list comprehension total = 0 partial_sums = [total := total + v for v in values] print("Total:", total)

However, an assignment expression target name cannot be the same as a for -target name appearing in any comprehension containing the assignment expression. The latter names are local to the comprehension in which they appear, so it would be contradictory for a contained use of the same name to refer to the scope containing the outermost comprehension instead.

For example, [i := i+1 for i in range(5)] is invalid: the for i part establishes that i is local to the comprehension, but the i := part insists that i is not local to the comprehension. The same reason makes these examples invalid too:

[[(j := j) for i in range(5)] for j in range(5)] # INVALID [i := 0 for i, j in stuff] # INVALID [i+1 for i in (i := stuff)] # INVALID

While it's technically possible to assign consistent semantics to these cases, it's difficult to determine whether those semantics actually make sense in the absence of real use cases. Accordingly, the reference implementation will ensure that such cases raise SyntaxError , rather than executing with implementation defined behaviour.

This restriction applies even if the assignment expression is never executed:

[False and (i := 0) for i, j in stuff] # INVALID [i for i, j in stuff if True or (j := 1)] # INVALID

For the comprehension body (the part before the first "for" keyword) and the filter expression (the part after "if" and before any nested "for"), this restriction applies solely to target names that are also used as iteration variables in the comprehension. Lambda expressions appearing in these positions introduce a new explicit function scope, and hence may use assignment expressions with no additional restrictions.

Due to design constraints in the reference implementation (the symbol table analyser cannot easily detect when names are re-used between the leftmost comprehension iterable expression and the rest of the comprehension), named expressions are disallowed entirely as part of comprehension iterable expressions (the part after each "in", and before any subsequent "if" or "for" keyword):

[i+1 for i in (j := stuff)] # INVALID [i+1 for i in range(2) for j in (k := stuff)] # INVALID [i+1 for i in [j for j in (k := stuff)]] # INVALID [i+1 for i in (lambda: (j := stuff))()] # INVALID

A further exception applies when an assignment expression occurs in a comprehension whose containing scope is a class scope. If the rules above were to result in the target being assigned in that class's scope, the assignment expression is expressly invalid. This case also raises SyntaxError :

class Example: [(j := i) for i in range(5)] # INVALID

(The reason for the latter exception is the implicit function scope created for comprehensions -- there is currently no runtime mechanism for a function to refer to a variable in the containing class scope, and we do not want to add such a mechanism. If this issue ever gets resolved this special case may be removed from the specification of assignment expressions. Note that the problem already exists for using a 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.