我正在努力解决我面临的这个奇怪问题。假设我们有一个defaultdict
对象的以下实例:
import dill
from collections import defaultdict
a = 1
b = 2
default_value = a/b
dict_with_default = defaultdict(lambda: default_value)
dict_with_default['a'] = 1.2
dict_with_default['b'] = 3.5
dict_with_default['c'] = 0.25
让我们看一下字典的样子:
defaultdict(<function <lambda> at 0x7f860c97be18>, {'a': 1.2, 'b': 3.5, 'c': 0.25})
在保存到dill
对象之前,我要检查字典是否正常工作-它可以并添加了'd'
:
print("d: ", dict_with_default['d'])
字典现在看起来像这样:
defaultdict(<function <lambda> at 0x7f860c97be18>, {'a': 1.2, 'b': 3.5, 'c': 0.25, 'd': 0.5})
由于我必须将字典保存到文件(以便将其传输到其他脚本),因此将其保存到dill
对象:
with open('./pickles/simple_dict_dill.p', 'wb') as file:
dill.dump(dict_with_default, file, protocol=dill.HIGHEST_PROTOCOL)
现在让我们将注意力转向我提到的其他脚本:
import dill
with open('./pickles/simple_dict_dill.p', 'rb') as file:
simple_dict_dill = dill.load(file)
print("a:", simple_dict_dill['a'])
print("d:", simple_dict_dill['d'])
print("e:", simple_dict_dill['e']) # gives error
即使print("e:", simple_dict_dill['e'])
处理了缺少键的访问,行lambda: default_value
也会出现以下错误:
NameError: name 'default_value' is not defined
我以为dill
可以序列化lambda函数,但事实证明它存在问题。
答案 0 :(得分:1)
我是dill
的作者。这是由于在全局字典之外定义lambda
时如何对其进行序列化。您可以通过两种方法避免此错误:(1)使用recurse
设置,或(2)在全局字典中定义lambda,而无需悬空指针。
例如:
>>> import dill
>>> dill.settings['recurse'] = True
>>> from collections import defaultdict
>>> a = 1
>>> b = 2
>>> f = lambda: a/b
>>> d = defaultdict(f)
>>> d['a'] = 3
>>> d['b'] = 4
>>> dill.dumps(d)
b'\x80\x03ccollections\ndefaultdict\nq\x00cdill._dill\n_create_function\nq\x01(cdill._dill\n_load_type\nq\x02X\x08\x00\x00\x00CodeTypeq\x03\x85q\x04Rq\x05(K\x00K\x00K\x00K\x02KCC\x08t\x00t\x01\x1b\x00S\x00q\x06N\x85q\x07X\x01\x00\x00\x00aq\x08X\x01\x00\x00\x00bq\t\x86q\n)X\x07\x00\x00\x00<stdin>q\x0bX\x08\x00\x00\x00<lambda>q\x0cK\x01C\x00q\r))tq\x0eRq\x0f}q\x10(h\x08K\x01h\tK\x02uh\x0cNN}q\x11tq\x12Rq\x13\x85q\x14Rq\x15(h\x08K\x03h\tK\x04u.'
然后我将生成的字符串(而不是写入文件……是同一件事)剪切-N-粘贴到新的python会话中。
$ python
Python 3.6.9 (default, Jul 6 2019, 02:58:03)
[GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.39.2)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import dill
>>> d = dill.loads(b'\x80\x03ccollections\ndefaultdict\nq\x00cdill._dill\n_create_function\nq\x01(cdill._dill\n_load_type\nq\x02X\x08\x00\x00\x00CodeTypeq\x03\x85q\x04Rq\x05(K\x00K\x00K\x00K\x02KCC\x08t\x00t\x01\x1b\x00S\x00q\x06N\x85q\x07X\x01\x00\x00\x00aq\x08X\x01\x00\x00\x00bq\t\x86q\n)X\x07\x00\x00\x00<stdin>q\x0bX\x08\x00\x00\x00<lambda>q\x0cK\x01C\x00q\r))tq\x0eRq\x0f}q\x10(h\x08K\x01h\tK\x02uh\x0cNN}q\x11tq\x12Rq\x13\x85q\x14Rq\x15(h\x08K\x03h\tK\x04u.')
>>> d
defaultdict(<function <lambda> at 0x101d8d048>, {'a': 3, 'b': 4})
>>> d['a']
3
>>> d['c']
0.5
>>>
如果您不使用recurse
设置,则必须使用:
>>> f = lambda: 1/2
>>> d = defaultdict(f)
创建默认字典时。
当然,dill
应该能够更好地处理来自lambda的指针引用,但是在某些情况下还不能。