Python 为什么分配给多个目标(标识符/属性)会产生奇怪的结果?

Python 为什么分配给多个目标(标识符/属性)会产生奇怪的结果?,python,variable-assignment,Python,Variable Assignment,我有一些这样的代码: def foo(): bar = initial_bar = Bar() while True: next_bar = Bar() bar.next_bar = next_bar bar = next_bar return initial_bar 其目的是形成一条链状的条s,可采用链表式 这一切都很好;但是由于一些错误的想法,我想把它减少一行,把循环末尾的赋值组合成一行 def foo():

我有一些这样的代码:

def foo():
    bar = initial_bar = Bar()
    while True:
        next_bar = Bar()
        bar.next_bar = next_bar
        bar = next_bar
    return initial_bar
其目的是形成一条链状的
s,可采用链表式

这一切都很好;但是由于一些错误的想法,我想把它减少一行,把循环末尾的赋值组合成一行

def foo():
    bar = initial_bar = Bar()
    while True:
        next_bar = Bar()
        bar = bar.next_bar = next_bar
    return initial_bar
因为
bar=bar.next\u bar=next\u bar
将扩展到
bar.next\u bar=next\u bar
,后面紧跟着有效的
bar=bar.next\u bar
。(除了它没有)

问题是,这不起作用;返回的“初始条”未定义其下一条。通过返回到更明确的两行解决方案,我可以很容易地解决这个问题,但到底发生了什么?

是时候退出了

如果你仔细观察,你会发现在临界线(第5行,见左边的数字,位置31-47),它是这样做的:

  • 加载下一个工具栏(31)两次(34)
  • 将其(堆栈上的第一个副本)写入
    (35)
    
  • 将其(堆栈上的第二个副本)写入
    条。下一个
    条(38,41)
这在一个最小的测试用例中更为明显

>>> def a():
...     b = c = d
... 
>>> dis.dis(a)
  2           0 LOAD_GLOBAL              0 (d)
              3 DUP_TOP             
              4 STORE_FAST               0 (b)
              7 STORE_FAST               1 (c)
             10 LOAD_CONST               0 (None)
             13 RETURN_VALUE        
看看它在做什么。这意味着
b=c=d
实际上等同于
b=d;c=d
。通常情况下,这并不重要,但在最初提到的情况下,这确实很重要。这意味着在关键时刻

bar = bar.next_bar = next_bar
不等于

bar.next_bar = next_bar
bar = next_bar
而是

bar = next_bar
bar.next_bar = next_bar
事实上,Python文档的第6.2节记录了这一点:

赋值语句计算表达式列表(请记住,这可以是单个表达式或逗号分隔列表,后者生成元组),并将单个结果对象从左到右分配给每个目标列表

该节中还有一条适用于本案的相关警告:

警告:虽然赋值的定义意味着左侧和右侧之间的重叠是“安全的”(例如
a,b=b,a
交换两个变量),但赋值变量集合内的重叠是不安全的!例如,以下程序打印
[0,2]

x = [0, 1]
i = 0
i, x[i] = 1, 2
print x
可以选择
bar.next_bar=bar=next_bar
,这确实产生了最初想要的结果,但请同情那些以后不得不阅读代码的人(包括原作者!),并为这样一个事实感到高兴,我相信Tim如果想到这些话,一定会用这些话

显式比潜在的令人困惑的情况要好


为什么要问这个问题?你在35分钟前贴的,35分钟前自我回复的。某种形式的博客更适合这种情况。@mmgp:我承认我一直认为这意味着“在你找到解决问题的方法后,你可以问自己的问题并回答自己的问题,而你在问之前并不知道。”。阅读您包含的链接,它清楚地表明事实并非如此,我很惊讶。@mmgp:另外,请查看页面。它通过在实现这一目标的最底层拥有一种手段来鼓励它。
x = [0, 1]
i = 0
i, x[i] = 1, 2
print x