<p>这种行为至少在一定程度上与解释器如何进行常量折叠有关
以及REPL如何执行代码。在</p>
<p>首先,请记住CPython首先编译代码(到AST,然后编译字节码)。然后评估
字节码。在编译期间,脚本查找不可变的对象并将其缓存。它
还可以对它们进行重复数据消除。所以如果它看到</p>
<pre><code>a = 257
b = 257
</code></pre>
<p>它将针对同一对象存储a和b:</p>
^{pr2}$
<p>注意<code>LOAD_CONST 1</code>。<code>1</code>是<code>co_consts</code>的索引:</p>
<pre><code>f.__code__.co_consts
#>>> (None, 257)
</code></pre>
<p>所以这两个加载相同的<code>257</code>。为什么不出现这种情况:</p>
<pre><code>$ python2
Python 2.7.8 (default, Sep 24 2014, 18:26:21)
>>> a = 257
>>> b = 257
>>> a is b
False
$ python3
Python 3.4.2 (default, Oct 8 2014, 13:44:52)
>>> a = 257
>>> b = 257
>>> a is b
False
</code></pre>
<p>是吗?在</p>
<p>本例中的每一行都是一个单独的编译单元,并且
重复数据消除无法在它们之间进行。它的工作原理与</p>
<pre><code>compile a = 257
run a = 257
compile b = 257
run b = 257
compile a is b
run a is b
</code></pre>
<p>因此,这些代码对象都将具有唯一的常量缓存。
这意味着如果删除换行符,<code>is</code>将返回<code>True</code>:</p>
<pre><code>>>> a = 257; b = 257
>>> a is b
True
</code></pre>
<p>实际上,这两个Python版本都是如此。事实上,这就是为什么</p>
<pre><code>>>> a, b = 257, 257
>>> a is b
True
</code></pre>
<p>也返回<code>True</code>;这不是因为解包的任何属性;它们
放在同一个编译单元。在</p>
<p>对于没有正确折叠的版本,返回<code>False</code>;<a href="https://stackoverflow.com/questions/27443857/what-is-with-this-change-of-unpacking-behavior-from-python2-to-python3/27445745#comment43331278_27444692">filmor links to Ideone</a>,这表明在2.7.3和3.2.3上失败。在这些版本中,创建的元组不会与其他常量共享它们的项:</p>
<pre><code>import dis
def f():
a, b = 257, 257
print(a is b)
print(f.__code__.co_consts)
#>>> (None, 257, (257, 257))
n = f.__code__.co_consts[1]
n1 = f.__code__.co_consts[2][0]
n2 = f.__code__.co_consts[2][1]
print(id(n), id(n1), id(n2))
#>>> (148384292, 148384304, 148384496)
</code></pre>
<p>不过,这并不是关于对象解包方式的改变,而是对象在<code>co_consts</code>中的存储方式的改变。在</p>