Python 不一致cPickle

Python 不一致cPickle,python,pickle,Python,Pickle,为什么以下代码在作为脚本运行时会产生错误?在交互式shell(剪切和粘贴)中运行时不会产生错误 泡菜的区别如下: $ python /tmp/picklefun.py Traceback (most recent call last): File "/tmp/picklefun.py", line 10, in <module> assert pickval1 == pickval2, (pickval1, pickval2) AssertionError: ('\x80

为什么以下代码在作为脚本运行时会产生错误?在交互式shell(剪切和粘贴)中运行时不会产生错误

泡菜的区别如下:

$ python /tmp/picklefun.py
Traceback (most recent call last):
  File "/tmp/picklefun.py", line 10, in <module>
    assert pickval1 == pickval2, (pickval1, pickval2)
AssertionError: ('\x80\x02}q\x01(U\x07fooblahq\x02]U\x02xyq\x03]u.',
                 '\x80\x02}q\x01(U\x07fooblah]U\x02xy]u.')
$python/tmp/picklefun.py
回溯(最近一次呼叫最后一次):
文件“/tmp/picklefun.py”,第10行,在
断言pickval1==pickval2,(pickval1,pickval2)
断言错误:('\x80\x02}q\x01(U\x07fooblahq\x02]U\x02xyq\x03]U.',
'\x80\x02}q\x01(U\x07fooblah]U\x02xy]U.)

似乎是由
cPickle
引起的,因为使用普通的
pickle
(我能够重现您的错误)

这就是为什么,第一级…我会继续研究,因为这是一个有趣的发现

更新:

cPickle文档(特别是脚注)保证对象总是被正确读取,但不保证(或保留)序列化数据总是相等。这可能不是意外行为,但值得注意


如果更换管路

val1 = dict(fooblah=[], xy=[])

然后,资产再次通过

为什么?答案深藏在cPickle的奥秘中。它有一个优化功能,可以查看某些对象的引用计数器是否小于2,并在这种情况下避免几个字节(通常用于检测同一个可能较大的字符串的周期或多次出现)。这是关于字符串对象“fooblah”和“xy”的。对于
exec
或以交互方式运行时,在pickle时,对字符串的引用只保留在字典中;引用计数器为1,因此cPickle会避免几个字节。但如果将示例作为模块编写,则该模块在该时间仍然处于活动状态,并且它会保留对字符串的另一个引用以常量形式存储


编辑澄清:第二次pickle时,我们将pickle一个字典,其中总是有来自取消pickle的新键——引用计数器1。因此,当且仅当第一次引用计数器1的键where时,断言才会通过。

我还复制了:Windows RT上的Python 2.7.3。
cPickle
失败;
pickle
没有。很高兴知道您能够复制它。有几个问题需要回答(1)为什么pickval1!=pickval2,以及(2)为什么它在作为脚本运行时会产生错误,而在以交互方式运行时不会产生错误。第二个错误更让IMHO感到不安。
pickle.loads
的结果是等效的,即使序列化版本不同,这一事实也让我不那么担心(2)。这很有趣,希望对您发现的差异有更多了解的人能给我们一些启发。但我很容易知道,这两个字符串代表同一个对象,希望这是最重要的。这可以通过将eval替换为:```val1=dict()exec'val1[“fooblah”]=[]来进行双重检查“exec”val1[“xy”]=[]```
val1 = dict(fooblah=[], xy=[])
exec "val1 = dict(fooblah=[], xy=[])"