Python 解包陷阱(意外行为)

标签 python iterable-unpacking

有人能解释一下这是怎么回事吗?为什么会出现这种情况?

>>> b = "1984"
>>> a = b, c = "AB"
>>> print(a, b, c)
'AB', 'A', 'B'

这种行为真的让我大吃一惊。 找到这个here

最佳答案

赋值是一个语句;它被定义为将最右侧从左到右分配给各个目标。比较干燥language grammar description is :

An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and assigns the single resulting object to each of the target lists, from left to right.

例如:

a = b = 1

1 分配给 a,然后再次将其分配给 b,与您的操作大致相同:

__specialtmp = 1
a = __specialtmp
b = __specialtmp

其中__specialtmp是一个未命名的临时存储位置(在CPython上,它只是加载到程序堆栈的顶部,然后复制到两个引用中,然后弹出每个引用以进行分配)。

这只是添加了可迭代的拆包;以同样的方式扩展您的代码,它看起来像:

__specialtmp = "AB"
a = __specialtmp  # Assigns original value to a
b, c = __specialtmp  # Unpacks string as iterable of its characters, assigning "A" to b, and "B" to c

请注意,这并不总是有效;如果被解包的东西是一个迭代器,并且您首先分配给解包的名称,则迭代器将耗尽,并且对于第二次分配将没有任何有用的信息:

b, c = [*a] = iter("AB")

这会将 "A" 解压为 b,将 "B" 解压为 c,但是当它得到时到 a,简单来说,[*a] = iter("AB") 将变为 ["A", "B"] (星形语法将“剩余”值捕获到列表中),在这种情况下,迭代器会耗尽填充 bc a 什么也没有(空的列表[])。

重点是,虽然这个技巧有效,但我一般不会推荐它。将多个名称初始化为相同的不可变值是可以的,但否则可能会造成困扰。

关于Python 解包陷阱(意外行为),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59276156/

相关文章:

python - Flask 从同一台计算机进行多次登录

python - 如何从 python 网站中提取出站链接?

python - Python 中按表达式对列表列表进行排序

java - Maven 依赖项 jar 不可用

python - 如何使用枚举解压元组列表?

Scala:元组的并行分配

python - 如何在 Flask/Jinja 中选择/减少字典列表

python - 正则表达式返回 2 个组

python - 解压特定索引

python-3.x - 首先解构/解包,然后在 Clojure 中休息