为什么Python的赋值不返回值?

73 投票
5 回答
29778 浏览
提问于 2025-04-16 11:03

为什么在Python中,赋值是一个语句而不是一个表达式呢?如果赋值是一个表达式,能够返回右边的值,这样在某些情况下代码会变得更简洁。有没有我看不到的问题呢?

举个例子:

# lst is some sequence
# X is come class
x = X()
lst.append(x)

可以改写成:

lst.append(x = X())

其实,准确来说,上面的写法是行不通的,因为x会被当作关键字参数处理。不过,如果再加一对括号(或者用其他符号来表示关键字参数),就能解决这个问题了。

5 个回答

15

现实中的答案是:其实并不需要。

在C语言中,你看到这种情况大多数是因为错误处理是手动进行的:

if((fd = open("file", O_RDONLY)) == -1)
{
    // error handling
}

类似的,很多循环的写法也是这样:

while(i++ < 10)
    ;

而在Python中,这些常见的情况处理得不一样。错误处理通常使用异常处理;循环通常使用迭代器。

反对这种做法的理由并不是特别惊人,但与在Python中这件事本身并不那么重要相比,这些理由就显得微不足道了。

41

从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 赋值(这在你给一个被重载的类的下标或属性赋值时可能会影响到,因为这可能会产生一些副作用)。

52

很多人觉得在像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是局部的,因为有赋值的关系。如果把赋值放在更复杂的表达式或语句中,这可能会让人更加困惑(比现在已经复杂的情况还要复杂)。

撰写回答