Python在defaultdict中

时间:2019-07-30 10:32:58

标签: python lambda pickle dill

我正在努力解决我面临的这个奇怪问题。假设我们有一个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函数,但事实证明它存在问题。

1 个答案:

答案 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的指针引用,但是在某些情况下还不能。