Tie*_*ung 18 python python-2.7 python-3.x difference iterable-unpacking
昨天我在Python 2和Python 3之间遇到了这个奇怪的解包差异,并且在快速谷歌搜索之后似乎没有找到任何解释.
Python 2.7.8
a = 257
b = 257
a is b # False
a, b = 257, 257
a is b # False
Run Code Online (Sandbox Code Playgroud)
Python 3.4.2
a = 257
b = 257
a is b # False
a, b = 257, 257
a is b # True
Run Code Online (Sandbox Code Playgroud)
我知道它可能不会影响程序的正确性,但它确实让我有点烦恼.任何人都可以在拆包时给出一些关于这种差异的见解吗?
Vee*_*rac 24
这种行为至少部分与解释器如何进行常量折叠以及REPL如何执行代码有关.
首先,请记住CPython首先编译代码(到AST然后是字节码).然后它评估字节码.在编译期间,脚本会查找不可变的对象并对其进行缓存.它还对它们进行重复数据删除.如果它看到了
a = 257
b = 257
Run Code Online (Sandbox Code Playgroud)
它会将a和b存储在同一个对象上:
import dis
def f():
a = 257
b = 257
dis.dis(f)
#>>> 4 0 LOAD_CONST 1 (257)
#>>> 3 STORE_FAST 0 (a)
#>>>
#>>> 5 6 LOAD_CONST 1 (257)
#>>> 9 STORE_FAST 1 (b)
#>>> 12 LOAD_CONST 0 (None)
#>>> 15 RETURN_VALUE
Run Code Online (Sandbox Code Playgroud)
请注意LOAD_CONST 1.该1是索引co_consts:
f.__code__.co_consts
#>>> (None, 257)
Run Code Online (Sandbox Code Playgroud)
所以这些都加载相同257.为什么不出现这种情况:
$ 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
Run Code Online (Sandbox Code Playgroud)
?
在这种情况下,每一行都是一个单独的编译单元,重复数据删除不能跨越它们.它的工作原理类似于
compile a = 257
run a = 257
compile b = 257
run b = 257
compile a is b
run a is b
Run Code Online (Sandbox Code Playgroud)
因此,这些代码对象都将具有唯一的常量缓存.这意味着如果我们删除换行符,is将返回True:
>>> a = 257; b = 257
>>> a is b
True
Run Code Online (Sandbox Code Playgroud)
事实上,这两个Python版本都是如此.事实上,这正是原因所在
>>> a, b = 257, 257
>>> a is b
True
Run Code Online (Sandbox Code Playgroud)
也回来True了; 这不是因为解包的任何属性; 它们只是放在同一个编译单元中.
这将返回False不正确折叠的版本; 电影或链接到Ideone,显示2.7.3和3.2.3失败.在这些版本中,创建的元组不会与其他常量共享其项目:
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)
Run Code Online (Sandbox Code Playgroud)
但是,这不是关于如何解开对象的变化; 它只是对象存储方式的改变co_consts.
我认为这实际上是偶然的,因为我不能用Python 3.2重现这种行为.
这个问题http://bugs.python.org/issue11244引入了一个CONST_STACK修复常量元组的问题,其中负数未被优化(查看补丁peephole.c,其中包含Python的优化运行).
这似乎也导致了给定的行为.还在调查这个:)
| 归档时间: |
|
| 查看次数: |
720 次 |
| 最近记录: |