With Python 3.8 Assignment Expressions have been introduced, allowing to assign values in conditionals and lambdas as such:
if x := True:
print(x)
However it appears this does not extends to attribute assignment, as trying to do something like this
from typing import NamedTuple
class Test(NamedTuple):
field : bool
test = Test(field=False)
if test.field := True:
print(test.field)
Will result in the following error:
SyntaxError: cannot use named assignment with attribute
Is it really only possible to update attribute in assignment statements (as opposed to assignment expressions) and if yes why this limitation?
A statement attempts to assign a value to an expression. You can assign a value only to a writable variable, property, or array element at run time. The following example illustrates how this error can occur.
Expression assignExpr = Expression.Assign ( variableExpr, Expression.Constant ("Hello World!") ); // The block expression allows for executing several expressions sequentually. // In this block, we pass the variable expression as a parameter, // and then assign this parameter a value in the assign expression.
If the statement assigns a value to an expression, replace the expression with a single writable variable, property, or array element. If the statement makes indirect access through a value type (usually a structure), create a variable to hold the value type. Assign the appropriate structure (or other value type) to the variable.
You can assign a value only to a writable variable, property, or array element at run time. The following example illustrates how this error can occur. VB. Dim yesterday As Integer ReadOnly maximum As Integer = 45 yesterday + 1 = DatePart (DateInterval.Day, Now) ' The preceding line is an ERROR because of an expression on the left.
From the pep:
Differences between assignment expressions and assignment statements
Most importantly, since
:=
is an expression, it can be used in contexts where statements are illegal, including lambda functions and comprehensions.Conversely, assignment expressions don't support the advanced features found in assignment statements:
- Single assignment targets other than a single
NAME
are not supported:# No equivalent a[i] = x self.rest = []
Seems like it was just made to avoid things that are too complicated (Which is a sign that it should probably be turned into a full statement somewhere). Also, this can already be achieved with setattr
:
# This is not that readable, but has the same semantics as what you asked for
if (setattr(test, 'field', new_test_field := ...), new_test_field)[1]:
...
# More readable with a helper function
def set_member(obj, member_name, new_value):
setattr(obj, member_name, new_value)
return new_value
if set_member(test, 'field', ...):
...
# But you might have wanted to check the new `test.field`
# instead of what you assigned it (In case it was a getter/setter descriptor)
def set_member(obj, member_name, new_value):
setattr(obj, member_name, new_value)
return getattr(obj, member_name)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With