Python解包陷阱(意外行为)

问题描述 投票:1回答:4

有人可以解释这是怎么回事吗?为什么会这样?

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

这种行为确实让我震惊。找到了这个here

python python-3.x python-2.7 iterable-unpacking
4个回答
1
投票

转让是一种声明;它的定义是将最右边从左到右分配给各个目标。比较干的language grammar description is

一个赋值语句评估表达式列表(请记住,它可以是单个表达式或逗号分隔的列表,后者产生一个元组),并将单个结果对象从左到右分配给每个目标列表。 >

例如:

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

这并不总是能引起您的注意;如果要解压缩的东西是一个迭代器,并且您为解压缩后的名称分配了[[first

,则该迭代器将被耗尽,并且对第二次分配没有任何用处:b, c = [*a] = iter("AB")
[将"A"分解为b,然后将"B"分解为c,但是当到达a时,通常[*a] = iter("AB")将变成["A", "B"](星型语法捕获“剩余”值)到list),在这种情况下,迭代器将用尽bc,并且a变得

nothing

(空的list[])。重点是,尽管此技巧可行,但一般情况下我不建议这样做。将多个名称初始化为相同的不变值是可以的,但是如果不这样做,很可能会咬你。

一个很酷的问题!很有趣! :)可以在面试中使用:)

好,我们到了

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

在python中,有多个分配,您可以省略(...),看起来python类似于2行都解析了这一行

a = "AB" b, c = "AB" # which is equal to (b, c) = "AB"

更多示例

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

它很好地使用列表:)

>>> a = [b, c] = 'AB' >>> print((a,b,c)) ('AB', 'A', 'B') >>>

更多示例:

  • 让我们简化一点。让我们看看以下情况

    >>> b = 1 >>> b, c = (0, 2) >>> print(b, c) 0, 2

    b为0而不是1感到惊讶吗?这不应该是因为由于元组拆包,我们在调用b时将c赋给0,将b, c = (0, 2)赋给2。

    现在解决陷阱的另一部分,让我们举个例子

    >>> b = 1 >>> a = b = 0 >>> print (b) 0

    再次令人惊讶的是b为0而不是1?再一次,这不应该是因为调用a = b = 0时,我们已经通过多次分配将ab都分配了0。

    所以回到陷阱,a = b, c = "AB"只是这两种行为的组合。 b, c = "AB"会将"A"打包到b,将"B"打包到c,我们还将"AB"分配到a。看起来我们正在分配a = b,实际上我们只是在执行以下两行

    >>> b = "1984" >>> b, c = "AB" >>> a = "AB"

    希望这可以分解发生元组拆包的位置和进行分配的位置,并且它不会像看起来那样令人困惑。

    似乎[

    c

    之间的,似乎分隔了2个不同的语句(或任何其他解释),但事实并非如此。a = b, c = "AB" ...当简单地分解时...
    a = "AB"
    #first assigning to *a* the string "AB"
    b, c = "AB"
    #then assigning to b and c the characters "A" and "B" , respectively
    
    

    也许这样想:

    b,c   =   (a  =  "AB")
    

  • 1
    投票
    一个很酷的问题!很有趣! :)可以在面试中使用:)

    0
    投票
    让我们简化一点。让我们看看以下情况

    0
    投票
    似乎[

    c

    © www.soinside.com 2019 - 2024. All rights reserved.