Python 为什么我不能指定一个命名表达式(LHS walrus运算符)?
赋值给表达式(而不是名称)在Python中很常见。例如,这是非常有效的语法:Python 为什么我不能指定一个命名表达式(LHS walrus运算符)?,python,syntax-error,python-3.8,walrus-operator,Python,Syntax Error,Python 3.8,Walrus Operator,赋值给表达式(而不是名称)在Python中很常见。例如,这是非常有效的语法: my.object["with_some"].very_long["expression"] = func(my.object["with_some"].very_long["expression"], my.object["with_some"].very_long["expression"])
my.object["with_some"].very_long["expression"] = func(my.object["with_some"].very_long["expression"], my.object["with_some"].very_long["expression"])
但是,如果我尝试使用walrus操作符通过使LHS成为一个命名表达式来缩短它,例如
(x:=my.object["with_some"].very_long["expression"]) = func(x, x)
Python引发了一个语法错误:
SyntaxError:无法分配给命名表达式
(x:=my.object["with_some"].very_long["expression"])
my.object["with_some"].very_long["expression"]
my.object["with_some"].very_long["expression"] = \
func(my.object["with_some"].very_long["expression"],
my.object["with_some"].very_long["expression"])
(x:=my.object["with_some"].very_long["expression"]) = func(x, x)
类似地,范围(5)中x[0]的是有效语法(非常容易混淆),而范围(5)
中(a:=x[0])的又是语法错误:无法分配给命名表达式
为什么我不能指定一个命名表达式?这是设计还是实施
提到了一些不能使用walrus运算符的情况,但除了一个以外,其他所有情况都与未加密表达式的语法有关,最后一个是关于f字符串的。与((self.x:=…)
中指出的情况不同,在我的例子中,walrus操作符中的赋值目标是一个简单的名称/标识符,而不是表达式。这两个方面都不清楚为什么不允许这样做。在撰写本文时,今天正好产生了三个结果:一,a(没有发生),和;谁也帮不了我
我无法指定给命名表达式的原因是什么?这是某个地方记录或定义的设计规则,还是实施限制?就我所见,它不会导致任何歧义,而且我的用例似乎应该是有效的。walrus操作符只作为副作用进行赋值-它的值不是左侧变量,而是右侧表达式的结果
因此,命名表达式的值
(x:=my.object["with_some"].very_long["expression"])
my.object["with_some"].very_long["expression"]
my.object["with_some"].very_long["expression"] = \
func(my.object["with_some"].very_long["expression"],
my.object["with_some"].very_long["expression"])
(x:=my.object["with_some"].very_long["expression"]) = func(x, x)
是walrus运算符右侧的结果(:=
),即。E表达式的结果
(x:=my.object["with_some"].very_long["expression"])
my.object["with_some"].very_long["expression"]
my.object["with_some"].very_long["expression"] = \
func(my.object["with_some"].very_long["expression"],
my.object["with_some"].very_long["expression"])
(x:=my.object["with_some"].very_long["expression"]) = func(x, x)
让我们将其表示为结果
,因此您的命令
(x:=my.object["with_some"].very_long["expression"]) = func(x, x)
与
result = func(x, x)
现在,结果
是一个值,而不是变量名。可能是None
,可能是一个数字,可能是一个特定的列表或其他内容,但不允许在赋值运算符的左侧
因此,赋值给命名表达式(至少在大多数情况下)是没有意义的,因此是不允许的。walrus操作符只作为副作用赋值-它的值不是左侧变量,而是右侧表达式的结果
my.object["with_some"].very_long["expression"] = \
func(my.object["with_some"].very_long["expression"],
my.object["with_some"].very_long["expression"])`
因此,命名表达式的值
(x:=my.object["with_some"].very_long["expression"])
my.object["with_some"].very_long["expression"]
my.object["with_some"].very_long["expression"] = \
func(my.object["with_some"].very_long["expression"],
my.object["with_some"].very_long["expression"])
(x:=my.object["with_some"].very_long["expression"]) = func(x, x)
是walrus运算符右侧的结果(:=
),即。E表达式的结果
(x:=my.object["with_some"].very_long["expression"])
my.object["with_some"].very_long["expression"]
my.object["with_some"].very_long["expression"] = \
func(my.object["with_some"].very_long["expression"],
my.object["with_some"].very_long["expression"])
(x:=my.object["with_some"].very_long["expression"]) = func(x, x)
让我们将其表示为结果
,因此您的命令
(x:=my.object["with_some"].very_long["expression"]) = func(x, x)
与
result = func(x, x)
现在,结果
是一个值,而不是变量名。可能是None
,可能是一个数字,可能是一个特定的列表或其他内容,但不允许在赋值运算符的左侧
因此,赋值给命名表达式(至少在大多数情况下)是没有意义的,因此是不允许的
my.object["with_some"].very_long["expression"] = \
func(my.object["with_some"].very_long["expression"],
my.object["with_some"].very_long["expression"])`
语法上的糖是什么
my.object["with_some"].very_long.__setitem__(
"expression",
func(my.object["with_some"].very_long["expression"],
my.object["with_some"].very_long["expression"]))
所以它不像你想象的那样对称。原始长表达式的值(而不是表达式本身)作为两个参数传递给func
,而原始表达式本身只是赋值的一种目标
然而,你可以写
x["expression"] = func(
(x:=my.object["with_some"].very_long)["expression"],
x["expression"])
当x
被分配一个通用表达式的值给被删除的版本时,my.object[“with_some”]。非常长
赋值表达式必须位于赋值的右侧,因为它在左侧之前求值。此外,它必须是使用:=
的第一个参数,因为函数参数保证从左到右求值
假设我正确定义了A
,下面是我用来验证上述方法是否有效的测试
class A:
def __init__(self, y):
self.b = dict(foo=y)
def func(x, y):
return x + y
a = A(A("bar"))
x["foo"] = func((x:=a.b["foo"].b)["foo"], x["foo"])
a.b[“foo”].b[“foo”]
的新值是“barbar”
,正如func
的定义所预期的那样
语法上的糖是什么
my.object["with_some"].very_long.__setitem__(
"expression",
func(my.object["with_some"].very_long["expression"],
my.object["with_some"].very_long["expression"]))
所以它不像你想象的那样对称。原始长表达式的值(而不是表达式本身)作为两个参数传递给func
,而原始表达式本身只是赋值的一种目标
然而,你可以写
x["expression"] = func(
(x:=my.object["with_some"].very_long)["expression"],
x["expression"])
当x
被分配一个通用表达式的值给被删除的版本时,my.object[“with_some”]。非常长
赋值表达式必须位于赋值的右侧,因为它在左侧之前求值。此外,它必须是使用:=
的第一个参数,因为函数参数保证从左到右求值
假设我正确定义了A
,下面是我用来验证上述方法是否有效的测试
class A:
def __init__(self, y):
self.b = dict(foo=y)
def func(x, y):
return x + y
a = A(A("bar"))
x["foo"] = func((x:=a.b["foo"].b)["foo"], x["foo"])
a.b[“foo”].b[“foo”]
的新值是“barbar”
,正如func
的定义所预期的那样,比较:
my.object["with_some"].very_long["expression"] = func(7, 7) # OK
与
解释如下:
在你的第一个表情中
(x:=my.object["with_some"].very_long["expression"])
my.object["with_some"].very_long["expression"]
my.object["with_some"].very_long["expression"] = \
func(my.object["with_some"].very_long["expression"],
my.object["with_some"].very_long["expression"])
(x:=my.object["with_some"].very_long["expression"]) = func(x, x)
您希望更改对象的属性的值(基于其当前属性的值),即按以下方式执行操作:
my.object["with_some"].very_long["expression"] = func(7, 7)
7 = func(7, 7)
在你的第二个表情中
(x:=my.object["with_some"].very_long["expression"])
my.object["with_some"].very_long["expression"]
my.object["with_some"].very_long["expression"] = \
func(my.object["with_some"].very_long["expression"],
my.object["with_some"].very_long["expression"])
(x:=my.object["with_some"].very_long["expression"]) = func(x, x)
赋值运算符(=)
的左侧不是对象的属性,而是对象的值。因此,您尝试将某个值赋值,即按
my.object["with_some"].very_long["expression"] = func(7, 7)
7 = func(7, 7)
发件人:
这是一个建议,用于创建一种在表达式中为变量赋值的方法
没有提到在分配的LHS中使用它。比较:
my.object["with_some"].very_long["expression"] = func(7, 7) # OK
与
解释如下:
在你的第一个表情中
(x:=my.object["with_some"].very_long["expression"])
my.object["with_some"].very_long["expression"]
my.object["with_some"].very_long["expression"] = \
func(my.object["with_some"].very_long["expression"],
my.object["with_some"].very_long["expression"])
(x:=my.object["with_some"].very_long["expression"]) = func(x, x)
您希望更改对象的属性的值(基于其当前属性的值),即执行以下操作