在 Python 中自我分配安全吗?

Is self assigning safe in Python?

这几天一直很困惑这个问题:在Python中将一个变量赋值给自己会发生什么?例如,

a = a if (a>b) else b

我对引用计数机制知之甚少,对这个问题一无所知。知道答案的帮帮我,谢谢!

绝对安全。 Python 将在 = 符号之后对所有内容进行排序,以便在分配变量之前计算表达式。 我认为没有任何编程语言不安全(请参阅下面@hadik 的评论)。


what happens to the reference counts of that variable when self assigning?

简而言之,它会做正确的事。

在更长的答案中,要回答这个问题,最好通过 运行 这段代码查看反汇编:

import dis                   
def f(a, b): 
    a = a if (a>b) else b                                               
dis.dis(f)

带注释的反汇编:

      # the objects pointed by `a` and `b` starts with a positive refcount as they're part of the function argument

      # increment refcount for the object pointed by `a` and `b`
      0 LOAD_FAST                0 (a)
      2 LOAD_FAST                1 (b)

      # COMPARE_OP (usually) returns boolean True/False
      # increment the refcount of the boolean value
      # and decrement the refcount of the object pointed by `a` and `b`
      4 COMPARE_OP               4 (>)

      # decrements the refcount of that boolean value
      6 POP_JUMP_IF_FALSE       12

      # increment refcount for the object pointed by `a`
      8 LOAD_FAST                0 (a)

     10 JUMP_FORWARD             2 (to 14)

      # increment refcount for the object pointed by `b`
>>   12 LOAD_FAST                1 (b)

      # decrement refcount for the object originally pointed by `a`
>>   14 STORE_FAST               0 (a)

     16 LOAD_CONST               0 (None)
     18 RETURN_VALUE

一些背景信息:Python VM 是堆栈计算机。 LOAD_* 操作将一个值压入堆栈(并增加它的引用计数,因为堆栈现在有对该对象的引用),大多数其他操作将从堆栈中弹出值并将计算结果压入堆栈(减少消耗的值并递增结果)。 STORE_* 操作将对象从栈顶移动到变量(并递减变量引用的原始对象的引用计数;不需要更改被移动对象的引用计数,因为弹出堆栈并设置有效地更改为变量不会更改引用计数)。

简而言之,Python refcount 即使在多线程时也总是做正确的事情(这要归功于 GIL)。你真的永远不需要担心引用计数,如果一个对象可以从一个范围内到达,它就不会被垃圾收集。