我正在学习 Python,一些与 print
相关的东西让我困惑。不确定是否有人问过同样的问题:
>>> x = 1
>>> x, y = x + 2, print(x)
1
我知道输出1
是Python的print
函数的副作用。但为什么它不打印 3
呢?我期待 3
因为 x
在第二行更新了?我认为它相当于(显然是错误的):
>>> x = 1
>>> x = x + 2
>>> x
3
>>> y = print(x)
3
我想了解这个 print
函数背后的逻辑。为什么它不打印更新的 x
值?
我是编程世界的新手,因此非常感谢任何见解!
最佳答案
首先评估右侧的所有内容。您可以使用 python 字节码反汇编器来查看发生了什么:
>>> import dis
>>> dis.dis('x, y = x + 2, print(x)')
1 0 LOAD_NAME 0 (x)
2 LOAD_CONST 0 (2)
4 BINARY_ADD
6 LOAD_NAME 1 (print)
8 LOAD_NAME 0 (x)
10 CALL_FUNCTION 1
12 ROT_TWO
14 STORE_NAME 0 (x)
16 STORE_NAME 2 (y)
18 LOAD_CONST 1 (None)
20 RETURN_VALUE
>>>
注意,x + 2
和 print(x)
首先计算。 BINARY_ADD 和 CALL_FUNCTION 出现在两个 STORE_NAME
之前。
注意,您可以将其视为相当于先构建一个元组,
temp = (x + 2, print(x))
然后简单地:
x, y = temp
但是,请注意,根据反汇编器,没有创建实际的中间元组。调用堆栈用于存储中间值。这是编译器优化。但是,优化不适用于长度大于 3 的元组,因此使用 4,您将看到创建了一个中间元组:
>>> dis.dis('foo, bar, baz, bang = bang, baz, bar, foo')
1 0 LOAD_NAME 0 (bang)
2 LOAD_NAME 1 (baz)
4 LOAD_NAME 2 (bar)
6 LOAD_NAME 3 (foo)
8 BUILD_TUPLE 4
10 UNPACK_SEQUENCE 4
12 STORE_NAME 3 (foo)
14 STORE_NAME 2 (bar)
16 STORE_NAME 1 (baz)
18 STORE_NAME 0 (bang)
20 LOAD_CONST 0 (None)
22 RETURN_VALUE
>>>
请注意 BUILD_TUPLE
和 UNPACK_SEQUENCE
,这是 Python 中解包工作的一般方式。只是编译器使用 ROT_TWO 和 ROT_THREE 操作码优化了两个或三个的常见情况。
注意,由于首先计算右侧,这使得 Python 交换习惯能够发挥作用!
x, y = y, x
如果这相当于:
x = y
y = x
如果不进行交换,您将会丢失 x 的值!
关于Python print 函数不返回更新后的变量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53717080/