在我昨天发布的post中,我意外地发现更改函数的__qualname__
会对pickle
产生意外的影响。通过运行更多的测试,我发现当酸洗一个函数时,pickle
并没有按照我的想法工作,并且更改函数的__qualname__
对pickle
的行为有实际的影响
下面的代码片段是我运行的测试
import pickle
from sys import modules
# a simple function to pickle
def hahaha(): return 1
print('hahaha',hahaha,'\n')
# change the __qualname__ of function hahaha
hahaha.__qualname__ = 'sdfsdf'
print('set hahaha __qualname__ to sdfsdf',hahaha,'\n')
# make a copy of hahaha
setattr(modules['__main__'],'abcabc',hahaha)
print('create abcabc which is just hahaha',abcabc,'\n')
try:
pickle.dumps(hahaha)
except Exception as e:
print('pickle hahaha')
print(e,'\n')
try:
pickle.dumps(abcabc)
except Exception as e:
print('pickle abcabc, a copy of hahaha')
print(e,'\n')
try:
pickle.dumps(sdfsdf)
except Exception as e:
print('pickle sdfsdf')
print(e)
通过运行代码段可以看到,hahaha
和abcabc
都无法被pickle,因为出现了异常:
Can't pickle <function sdfsdf at 0x7fda36dc5f28>: attribute lookup sdfsdf on __main__ failed
我真的被这个例外弄糊涂了
当pickle
对函数进行pickle时,它寻找什么?虽然hahaha
的__qualname__
已更改为“sdfsdf”,但函数hahaha
及其副本abcabc
仍然可以在会话中调用(就像在dir(sys.modules['__main__'])
中一样),那么为什么pickle
无法对它们进行pickle呢
更改函数的__qualname__
的实际效果是什么?我理解,将hahaha
的__qualname__
更改为'sdfsdf'不会使sdfsdf
可调用,因为它不会出现在dir(sys.modules['__main__'])
中。但是,通过运行代码段可以看到,在将hahaha
的__qualname__
更改为“sdfsdf”之后,对象hahaha
及其副本abcabc
已更改为类似<function sdfsdf at 'some_address'>
的内容。sys.modules['__main__']
和<function sdfsdf at 'some_address'>
中的对象之间有什么区别
函数对象的pickle在^{} method in pickle.py 中定义:
首先,通过
__qualname__
检索函数名:之后,在检索模块后,将重新导入该模块:
这个新导入的
module
然后用于作为属性查找函数:obj2
现在将是函数的新副本,但由于sdfsdf
在此模块中不存在,因此pickle失败你可以做到这一点,但你必须始终如一:
相关问题 更多 >
编程相关推荐