【问题标题】:Not enough values to unpack in chained assignment没有足够的值在链式赋值中解包
【发布时间】:2017-10-17 06:31:48
【问题描述】:

我知道这不是在一行中分配多个值的方法,但我只是想了解第 4 行在这里做了什么:

a = input("blah blah")
b = input("blah blah blah")
c = input("blaaah")
A=a,B=b,C=c
print(A,B,C)

如果 a,b,cintfloat 类型,则会显示 "int/float object is not iterable" 错误。

如果a,b,c 是字符串并且说a="ab",b="cd",c="ef",打印将显示:

ef f f

如果字符串的长度为!= 2,则会显示"not enough/too many values to unpack" 错误。

有人可以解释发生了什么吗?

【问题讨论】:

    标签: python python-3.x iteration iterable-unpacking


    【解决方案1】:

    你可以看一下反汇编,看看到底发生了什么:

    from dis import dis
    dis('A=a,B=b,C=c')
      1           0 LOAD_NAME                0 (c)
                  2 DUP_TOP
                  4 STORE_NAME               1 (A)
                  6 DUP_TOP
                  8 UNPACK_SEQUENCE          2
                 10 STORE_NAME               2 (a)
                 12 STORE_NAME               3 (B)
                 14 UNPACK_SEQUENCE          2
                 16 STORE_NAME               4 (b)
                 18 STORE_NAME               5 (C)
                 20 LOAD_CONST               0 (None)
                 22 RETURN_VALUE
    

    这是说链式赋值:

    A=a,B=b,C=c
    

    实际上评估为:

    A = c
    a, B = c 
    b, C = c
    

    这就是为什么如果您打印ab 的值,您会看到它们也等于'e'

    这也是为什么,如果 cab 在这里不起作用)是长度为 > 2 的字符串,则解包将失败。

    【讨论】:

    • ab 在那里没有任何作用是不正确的。如果您尝试A = 4, B = "aa",您将获得SyntaxError: can't assign to literal,如果您尝试获得A 的值,您将获得NameError: name 'A' is not defined
    • @nutmeg64 让我们再过一遍。发生的情况是尝试A = 'aa',然后尝试执行4, B = 'aa'。整个事情都失败了,因为这是在一个步骤中执行的,SyntaxError 阻止了整个分配,A 没有分配给你,你得到了NameError。尝试a = 1; b =3; A = a,b = 'ef' 并查看输出。
    • 没错。因此,您在“实际评估为:”下面的代码 sn-p 是不正确的。您在那里暗示分配 A = c 发生在之前任何其他分配。
    • @nutmeg64 A = c 发生在任何其他任务之前,我并不是在暗示,我是在公开声明。可以看到在字节码中,也可以看到by example。在前面的例子中,SyntaxError 只是阻止了整个事情的运行,这不是一个很好的例子来说明你关于在运行时发生的评估的观点。
    【解决方案2】:

    澄清: 我的回答没有解释“Python 解释器的工作原理”。我的回答中描述的一系列事件只是对情况的简化,以帮助初学者更好地理解它。

    这里发生的事情是这样的:

    A = (a, B) = (b, C) = c
    

    这就是解释器的看法。

    这是一个多重赋值语句。

    解释器尝试将c 解压缩为两个参数的可迭代对象。 然后尝试将第一个参数分配给b,将第二个参数分配给C

    下一步有一个简单的tuple to tuple两个参数赋值,其中(b, C)被解包并赋值为a = bB = C

    在最后一步中,需要将包含两个参数的 tuple 迭代解包并分配给A。因为A 是这里的一个新变量,所以元组不会解包,只需将 tuple 可迭代分配给A

    例如:

    >>> c = (1, 'one')
    >>> A = a, B = b, C = c
    >>> A
    (1, 'one')
    >>> B
    'one'
    >>> C
    'one'
    >>> a
    1
    >>> b
    1
    >>> c
    (1, 'one')
    

    【讨论】:

    • 嗯,没有。这不是发生的事情,我在我的答案中添加了反汇编,它显示了解释器实际在做什么。如果您的声明是正确的,则 A 将等于 ('e', 'f') 如果 c'ef'不是 'ef'
    • @JimFasarakisHilliard 已编辑。不要沉迷于小事;)
    • 再一次,这是不正确的。在多项作业中都采取了一套非常明确的步骤,而您是在歪曲它。
    • 我没有弄错,因为UNPACK_SEQUENCE 正是它的意思:解包一个可迭代对象(因为可迭代对象是一个序列)。如果您认为我对我所描述的 事件顺序 有误,那么我这样做只是为了简化对结果的解释。当然,这不是完全解释器做事的方式。我不认为了解解释器及其后端操作的一切
    • 以及关于该主题的进一步解释(Python 解释器如何工作)我认为只会让初学者程序员感到困惑。这就是为什么我不同意你的回答,也没有给它一个赞成票,因为这个问题的提问者显然是一个初学者。
    猜你喜欢
    • 2018-08-25
    • 1970-01-01
    • 1970-01-01
    • 2021-09-12
    • 2021-07-16
    • 1970-01-01
    • 2018-01-26
    • 2021-11-28
    • 2017-12-29
    相关资源
    最近更新 更多