为什么Python的赋值不返回值?
为什么在Python中,赋值是一个语句而不是一个表达式呢?如果赋值是一个表达式,能够返回右边的值,这样在某些情况下代码会变得更简洁。有没有我看不到的问题呢?
举个例子:
# lst is some sequence
# X is come class
x = X()
lst.append(x)
可以改写成:
lst.append(x = X())
其实,准确来说,上面的写法是行不通的,因为x
会被当作关键字参数处理。不过,如果再加一对括号(或者用其他符号来表示关键字参数),就能解决这个问题了。
5 个回答
现实中的答案是:其实并不需要。
在C语言中,你看到这种情况大多数是因为错误处理是手动进行的:
if((fd = open("file", O_RDONLY)) == -1)
{
// error handling
}
类似的,很多循环的写法也是这样:
while(i++ < 10)
;
而在Python中,这些常见的情况处理得不一样。错误处理通常使用异常处理;循环通常使用迭代器。
反对这种做法的理由并不是特别惊人,但与在Python中这件事本身并不那么重要相比,这些理由就显得微不足道了。
从Python 3.8开始(2019年10月发布),支持使用赋值(子)表达式,比如你可以把你的例子改写成 lst.append(x := X())
。
这个提议叫做 PEP 572,在2018年7月被Guido正式接受。之前也有过一些关于赋值表达式的提案,比如被撤回的 PEP 379。
记得在Python 3之前,print
是一个语句,而不是一个表达式。
像 x = y = z
这样的语句可以把同一个值赋给多个目标(或者说多个 目标列表,因为也允许解包),这在Python中早就支持了(比如从版本1开始),但它是通过一种特殊的 语法来实现的,而不是通过连续的赋值子表达式来实现。实际上,单个赋值的执行顺序是反向的:嵌套的海象运算符 (x := (y := z))
必须先给 y
赋值,然后才能给 x
赋值,而 x = y = z
则是先给 x
赋值,再给 y
赋值(这在你给一个被重载的类的下标或属性赋值时可能会影响到,因为这可能会产生一些副作用)。
很多人觉得在像Python这样的编程语言中,把赋值当作表达式来用,尤其是可以在条件中使用任何值(而不仅仅是布尔值),是容易出错的。可以推测,Guido(Python的创始人)也是这样认为的。一个经典的错误是:
if x = y: # oops! meant to say ==
在Python中,情况比在C语言中要复杂一些,因为在Python里,第一次给变量赋值就是在声明这个变量。例如:
def f():
print x
def g():
x = h()
print x
在这两个函数中,"print x
"这一行做的事情是不同的:一个是指向全局变量x
,而另一个是指向局部变量x
。在函数g
中的x
是局部的,因为有赋值的关系。如果把赋值放在更复杂的表达式或语句中,这可能会让人更加困惑(比现在已经复杂的情况还要复杂)。