每次程序都是不同的 cloudpickle 运行
Different cloudpickle everytime the program is run
考虑以下 python 代码:
import cloudpickle
class Foo:
def __init__(self, num):
self.num = num
def outer(num):
return Foo(num)
print(cloudpickle.dumps(outer))
每次您 运行 代码时都会产生不同的 pickle。使用 pickletools
分析 pickle 文件显示以下差异:
144c144
< 552: \x8c SHORT_BINUNICODE '2e3db4572bb349268962a75a8a6f034c'
---
> 552: \x8c SHORT_BINUNICODE '89ee770de9b745c4bbe83c353f1debba'
现在,我了解到 cloudpickle 不保证 运行pickle 文件的确定性。 (link),但我很好奇为什么这两个 pickle 文件不同。看起来上面的差异是因为 Foo
class.
的某种不同哈希
请注意,我运行 python 程序固定 PYTHONHASHSEED
。
PS:
这足以重现问题:
import pickletools
import cloudpickle
class Foo:
def __init__(self, num):
self.num = num
pickletools.dis(cloudpickle.dumps(Foo))
所以似乎每个 class 都有一个 属性 被烤到 cloudpickle 中,但我不知道那个 属性 是什么。
好奇!
我深入研究了源代码,发现它不是 class 的 属性,甚至不是计算的哈希值,它是 just a random identifier generated with uuid4()
per class。
该函数被 _class_getnewargs()
here, which is called by _dynamic_class_reduce()
here 调用,其中包含评论
Save a class that can't be stored as module global.
This method is used to serialize classes that are defined inside functions, or that otherwise can't be serialized as attribute lookups
from global modules.
如果 class 不在 __main__
模块中,事情就会简单得多(因为从最终的拆包者的角度来看,__main__
可以是任何东西);如果你做 from b import outer
和 cloudpickle that outer
,你会得到
0: \x80 PROTO 5
2: \x95 FRAME 15
11: \x8c SHORT_BINUNICODE 'b'
14: \x94 MEMOIZE (as 0)
15: \x8c SHORT_BINUNICODE 'outer'
22: \x94 MEMOIZE (as 1)
23: \x93 STACK_GLOBAL
24: \x94 MEMOIZE (as 2)
25: . STOP
因为泡菜而不是所有的巫毒 cloudpickle 会泡菜 __main__
中的东西。
考虑以下 python 代码:
import cloudpickle
class Foo:
def __init__(self, num):
self.num = num
def outer(num):
return Foo(num)
print(cloudpickle.dumps(outer))
每次您 运行 代码时都会产生不同的 pickle。使用 pickletools
分析 pickle 文件显示以下差异:
144c144
< 552: \x8c SHORT_BINUNICODE '2e3db4572bb349268962a75a8a6f034c'
---
> 552: \x8c SHORT_BINUNICODE '89ee770de9b745c4bbe83c353f1debba'
现在,我了解到 cloudpickle 不保证 运行pickle 文件的确定性。 (link),但我很好奇为什么这两个 pickle 文件不同。看起来上面的差异是因为 Foo
class.
请注意,我运行 python 程序固定 PYTHONHASHSEED
。
PS: 这足以重现问题:
import pickletools
import cloudpickle
class Foo:
def __init__(self, num):
self.num = num
pickletools.dis(cloudpickle.dumps(Foo))
所以似乎每个 class 都有一个 属性 被烤到 cloudpickle 中,但我不知道那个 属性 是什么。
好奇!
我深入研究了源代码,发现它不是 class 的 属性,甚至不是计算的哈希值,它是 just a random identifier generated with uuid4()
per class。
该函数被 _class_getnewargs()
here, which is called by _dynamic_class_reduce()
here 调用,其中包含评论
Save a class that can't be stored as module global. This method is used to serialize classes that are defined inside functions, or that otherwise can't be serialized as attribute lookups from global modules.
如果 class 不在 __main__
模块中,事情就会简单得多(因为从最终的拆包者的角度来看,__main__
可以是任何东西);如果你做 from b import outer
和 cloudpickle that outer
,你会得到
0: \x80 PROTO 5
2: \x95 FRAME 15
11: \x8c SHORT_BINUNICODE 'b'
14: \x94 MEMOIZE (as 0)
15: \x8c SHORT_BINUNICODE 'outer'
22: \x94 MEMOIZE (as 1)
23: \x93 STACK_GLOBAL
24: \x94 MEMOIZE (as 2)
25: . STOP
因为泡菜而不是所有的巫毒 cloudpickle 会泡菜 __main__
中的东西。