Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/324.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
使用pop()、list[-1]和+;=时,python中的求值顺序是什么?_Python_List_Operator Precedence_Indices - Fatal编程技术网

使用pop()、list[-1]和+;=时,python中的求值顺序是什么?

使用pop()、list[-1]和+;=时,python中的求值顺序是什么?,python,list,operator-precedence,indices,Python,List,Operator Precedence,Indices,这将导致[1,6] a = [1, 2, 3] a[-1] += a.pop() 这将导致[4,2]。什么样的评估顺序给出这两个结果?关键洞察是a[-1]+=a.pop()是a[-1]=a[-1]+a.pop()的语法糖。这是正确的,因为+=应用于不可变对象(此处为int),而不是可变对象() 首先评估右侧(RHS)。在RHS上:等效语法是a[-1]+a.pop()。首先,a[-1]获取最后一个值3。其次,a.pop()返回s3。 3+3是6 在左侧(LHS),a现在是[1,2],这是由于li

这将导致
[1,6]

a = [1, 2, 3]
a[-1] += a.pop()

这将导致
[4,2]
。什么样的评估顺序给出这两个结果?

关键洞察是
a[-1]+=a.pop()
a[-1]=a[-1]+a.pop()的语法糖。这是正确的,因为
+=
应用于不可变对象(此处为
int
),而不是可变对象()

首先评估右侧(RHS)。在RHS上:等效语法是
a[-1]+a.pop()
。首先,
a[-1]
获取最后一个值
3
。其次,
a.pop()
返回
s
3
3
+
3
6


在左侧(LHS),
a
现在是
[1,2]
,这是由于
list.pop()
已经应用了原位突变,因此对于特定示例,
a[-1]
的值从
2
更改为
6

a = [1, 2, 3]
a[0] += a.pop()
订单:

  • =
  • pop()
    ,减少
    a的长度
  • 加成
  • 分配
  • 问题是,
    a[-1]
    pop()之后成为
    a[1]
    (was
    a[2]
    )的值,但这发生在赋值之前

    a[-1] += a.pop() #is the same as 
    a[-1] = a[-1] + a.pop() # a[-1] = 3 + 3
    
    工作如期进行

  • =
  • pop()
  • 加成
  • 分配

  • 这个例子说明了为什么在处理列表时不应该操作它(通常称为循环)。在这种情况下,请始终使用复印机。

    先使用RHS,然后使用LHS。在任何一侧,求值顺序是从左到右

    a[-1]+=a.pop()
    与,
    a[-1]=a[-1]+a.pop()

    看看当我们改变RHS的操作顺序时行为是如何变化的

    a = [1,2,3]
    a[-1] = a[-1] + a.pop() # a = [1, 6]
    

    让我们看看for
    a[-1]+=a.pop()
    1)的输出:

    下面列出了不同说明的含义

    首先,
    LOAD\u FAST
    LOAD\u CONST
    a
    -1
    加载到堆栈上,并在
    BINARY\u SUBSCR
    获取下标值之前将两者复制,从而在堆栈上生成
    a,-1,3
    。然后再次加载
    a
    ,然后
    LOAD_ATTR
    加载
    pop
    函数,该函数由
    CALL_函数
    无参数调用。堆栈现在是
    a,-1,3,3
    ,并且
    INPLACE\u ADD
    添加前两个值。最后,
    ROT\u THREE
    将堆栈旋转到
    6,a,-1
    ,以匹配
    STORE\u SUBSCR
    所期望的顺序,并存储值

    因此,简而言之,
    a[-1]
    的当前值在调用
    a.pop()
    之前进行评估,然后将加法结果存储回新的
    a[-1]
    ,而不管其当前值如何



    1) 这是Python3的反汇编,略微压缩以更好地适应页面,并在
    #…
    之后添加了一列显示堆栈;对于Python 2,它看起来有点不同,但很相似。

    在带有调试打印语句的列表周围使用一个薄型包装器,可以用来显示案例中的求值顺序:

    3    15 LOAD_FAST            0 (a)                             # a,
         18 LOAD_CONST           5 (-1)                            # a, -1
         21 DUP_TOP_TWO                                            # a, -1, a, -1
         22 BINARY_SUBSCR                                          # a, -1, 3
         23 LOAD_FAST            0 (a)                             # a, -1, 3, a
         26 LOAD_ATTR            0 (pop)                           # a, -1, 3, a.pop
         29 CALL_FUNCTION        0 (0 positional, 0 keyword pair)  # a, -1, 3, 3
         32 INPLACE_ADD                                            # a, -1, 6
         33 ROT_THREE                                              # 6, a, -1
         34 STORE_SUBSCR                                           # (empty)
    
    当我现在运行您的示例时:

    class Test(object):
        def __init__(self, lst):
            self.lst = lst
    
        def __getitem__(self, item):
            print('in getitem', self.lst, item)
            return self.lst[item]
    
        def __setitem__(self, item, value):
            print('in setitem', self.lst, item, value)
            self.lst[item] = value
    
        def pop(self):
            item = self.lst.pop()
            print('in pop, returning', item)
            return item
    
    因此,它首先获取最后一项,即3,然后弹出最后一项,即3,添加它们并用
    6
    覆盖列表中的最后一项。因此,最终的列表将是
    [1,6]

    a = [1, 2, 3]
    a[-1] += a.pop()
    
    在第二种情况下:

    >>> a = Test([1, 2, 3])
    >>> a[-1] += a.pop()
    in getitem [1, 2, 3] -1
    in pop, returning 3
    in setitem [1, 2] -1 6
    
    现在将第一项(
    1
    )添加到弹出的值(
    3
    )中,并用总和覆盖第一项:
    [4,2]



    和已经解释了评估的一般顺序。这个答案只是补充了这里提到的一般原则。

    @tobias_k以第一个例子为例。a、 pop()返回3并将a更改为[1,2]。现在计算a[-1]=a[-1]+3得到的是5,而不是6。@felipa我猜Python首先将
    a[-1]+=a.pop()
    转换为
    a[-1]=a[-1]+a.pop()
    。这就是为什么您会得到
    6
    a[-1]
    a.pop()
    之前计算。如果您将其更改为
    a[-1]=a.pop()+a[-1]
    ,您将得到
    5
    ,尽管此页面上的多条注释似乎表明了相反的情况,请注意,通常
    a+=b
    a=a+b
    不同,并且不保证Python会将其翻译成这样。调用不同的方法。归根结底是不是同样的事情取决于操作数的类型。@Chris_Rands:我试着用我的话谨慎地说,这两个“一般”是不等价的,这取决于对象:我同意这在这里是合理的。(但另一方面,我不确定
    +
    +=
    运算符对于整数是等价的这一事实是回答这个问题的关键:如果涉及不同的对象,一般结果是相同的。我认为评估顺序是主要点。)PSA:永远不要编写依赖于这些细节的代码。即使它能工作,也不是好代码。如果您在自己的代码行上隔离副作用(这相当于每行修改一个状态),那么读取和修改代码会容易得多。在这种情况下,您应该执行
    a=[1,2,3];temp=a.pop();a[-1]=2*temp
    a=[1,2,3];temp=a.pop();a[-1]+=temp
    ,具体取决于您打算做什么。这使您的预期计算顺序更加明确,而且更容易正确。使用
    dis.dis的酷东西,我不知道这个!“在RHS,它是从左到右的”有趣的事实:虽然运算符当然是按w.r.t.运算符优先级计算的,但实际表达式显然不是,例如在
    f()+g()*h()
    中,fu
    >>> a = Test([1, 2, 3])
    >>> a[-1] += a.pop()
    in getitem [1, 2, 3] -1
    in pop, returning 3
    in setitem [1, 2] -1 6
    
    >>> a = Test([1, 2, 3])
    >>> a[0] += a.pop()
    in getitem [1, 2, 3] 0
    in pop, returning 3
    in setitem [1, 2] 0 4