print(*a, a.pop(0)) 如何改变?

Kel*_*ndy 64 python

这段代码:

a = [1, 2, 3]
print(*a, a.pop(0))
Run Code Online (Sandbox Code Playgroud)

Python 3.8 打印2 3 1(在解包之前进行pop)。
Python 3.9 打印1 2 3 1(解压后执行pop)。

是什么导致了这种变化?我在变更日志中没有找到它。

编辑:不仅在函数调用中,而且在列表显示中:

a = [1, 2, 3]
b = [*a, a.pop(0)]
print(b)
Run Code Online (Sandbox Code Playgroud)

打印[2, 3, 1]vs[1, 2, 3, 1]打印 表达式列表显示“表达式从左到右求值”(这是 Python 3.8 文档的链接),所以我希望首先发生解包表达式。

use*_*ica 53

我怀疑这可能是一次意外,尽管我更喜欢新的行为。

新行为是参数字节码工作方式更改的结果*。更改位于Python 3.9.0 alpha 3 下的更改日志中:

bpo-39320:用三个更简单的字节码替换用于构建序列的四个复杂字节码。

以下四个字节码已被删除:

  • BUILD_LIST_UNPACK
  • BUILD_TUPLE_UNPACK
  • 构建_设置_解压
  • BUILD_TUPLE_UNPACK_WITH_CALL

添加了以下三个字节码:

  • 列表到元组
  • 列表_EXTEND
  • 设置更新

在 Python 3.8 上, 的字节码f(*a, a.pop())如下所示:

  1           0 LOAD_NAME                0 (f)
              2 LOAD_NAME                1 (a)
              4 LOAD_NAME                1 (a)
              6 LOAD_METHOD              2 (pop)
              8 CALL_METHOD              0
             10 BUILD_TUPLE              1
             12 BUILD_TUPLE_UNPACK_WITH_CALL     2
             14 CALL_FUNCTION_EX         0
             16 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

而在 3.9 上,它看起来像这样:

  1           0 LOAD_NAME                0 (f)
              2 BUILD_LIST               0
              4 LOAD_NAME                1 (a)
              6 LIST_EXTEND              1
              8 LOAD_NAME                1 (a)
             10 LOAD_METHOD              2 (pop)
             12 CALL_METHOD              0
             14 LIST_APPEND              1
             16 LIST_TO_TUPLE
             18 CALL_FUNCTION_EX         0
             20 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)

在旧的字节码中,代码将a和压(a.pop(),)入堆栈,然后将这两个可迭代对象解压到一个元组中。在新的字节码中,代码将列表压入堆栈,然后执行l.extend(a)l.append(a.pop()),然后调用tuple(l)

此更改的效果是将解包转移a到调用之前pop,但这似乎不是故意的。查看bpo-39320,其目的是简化字节码指令,而不是更改行为,并且 bpo 线程没有讨论行为更改。

  • @marcelm 术语“加星号的表达式”可能只是指加星号的表达式;它并不意味着给一个表达式加注星标的结果是另一个表达式。比较一下术语“截断词”,这并不一定意味着像“flowe”(“flower”这个词的截断)之类的东西本身就是一个词。 (3认同)
  • 至于 print(a.pop(0), *a) ,无论版本如何,pop 都会在解包之前发生。 (2认同)