Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/354.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/python-2.7/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 如何将defaultdict of defaultdicts[of defaultdicts]转换为dict of dicts[of dicts]?_Python_Python 2.7_Dictionary_Collections - Fatal编程技术网

Python 如何将defaultdict of defaultdicts[of defaultdicts]转换为dict of dicts[of dicts]?

Python 如何将defaultdict of defaultdicts[of defaultdicts]转换为dict of dicts[of dicts]?,python,python-2.7,dictionary,collections,Python,Python 2.7,Dictionary,Collections,使用,我创建了一个defaultdict的defaultdict。现在,我想把这个嵌套很深的dict对象转换回一个普通的python dict from collections import defaultdict factory = lambda: defaultdict(factory) defdict = factory() defdict['one']['two']['three']['four'] = 5 # defaultdict(<function <lambda&

使用,我创建了一个
defaultdict
defaultdict
。现在,我想把这个嵌套很深的dict对象转换回一个普通的python dict

from collections import defaultdict

factory = lambda: defaultdict(factory)
defdict = factory()
defdict['one']['two']['three']['four'] = 5

# defaultdict(<function <lambda> at 0x10886f0c8>, {
#             'one': defaultdict(<function <lambda> at 0x10886f0c8>, {
#                 'two': defaultdict(<function <lambda> at 0x10886f0c8>, {
#                     'three': defaultdict(<function <lambda> at 0x10886f0c8>, {
#                         'four': 5})})})})

此外,由于它不会在嵌套的dict上递归,因此也不充分。

您可以在树上递归,用dict生成的dict替换每个
defaultdict
实例:

def default_to_regular(d):
    if isinstance(d, defaultdict):
        d = {k: default_to_regular(v) for k, v in d.items()}
    return d
演示:

>>从集合导入defaultdict
>>>工厂=lambda:defaultdict(工厂)
>>>defdict=工厂()
>>>定义一、二、三、四、五
>>>定义
defaultdict(,{'one':defaultdict(,{'two':defaultdict(,{'three':defaultdict(,{'four':5})})})
>>>默认值为常规值(defdict)
{'1':{'2':{'3':{'4':5}}
你要做的是pickle你的递归
defaultdict
。当取消勾选时,您不在乎是否返回
dict
defaultdict

虽然有很多方法可以解决这个问题(例如,用自己的pickle创建一个
defaultdict
子类,或者用
copyreg
显式覆盖默认的子类),但有一种方法非常简单

请注意尝试时出现的错误:

>>> pickle.dumps(defdict)
PicklingError: Can't pickle <function <lambda> at 0x10d7f4c80>: attribute lookup <lambda> on __main__ failed
你完成了

这就是它的作用:

>>> from collections import defaultdict
>>> def factory(): return defaultdict(factory)
>>> defdict = factory()
>>> defdict['one']['two']['three']['four'] = 5
>>> import pickle
>>> pickle.dumps(defdict)
b'\x80\x03ccollections\ndefaultdict\nq\x00c__main__\nfactory\nq\x01\x85q\x02Rq\x03X\x03\x00\x00\x00oneq\x04h\x00h\x01\x85q\x05Rq\x06X\x03\x00\x00\x00twoq\x07h\x00h\x01\x85q\x08Rq\tX\x05\x00\x00\x00threeq\nh\x00h\x01\x85q\x0bRq\x0cX\x04\x00\x00\x00fourq\rK\x05ssss.'

在其他情况下,如果使用
lambda
而不是
def
,如果没有充分的理由,则会导致问题,您无法在运行时同时反思您的函数,调试器中的回溯会更差,等等。如果您想要一个固有的匿名函数,请使用
lambda
,或者你可以在表达式中间定义一个函数,但是不要用它来保存三个字符的输入。

为什么你需要转换这些函数?如果你不想要一个<代码> Debug?< /代码>,你是否考虑过编写一个包装器,用普通的<代码> DICT</代码> S使用<代码> StimeDebug <代码>?在构建时让代码稍微复杂一点可能是一个更好的解决方案,而不是让代码稍微简单一点,然后再增加一个额外的复杂度…@abarnert我唯一的答案是上面的基本回答。。。。我对这个问题很好奇,认为使用reduce()或itertools之类的工具可能有一个聪明的解决方案。我知道我本可以问起酸洗的事。。。但我有点被困在这上面了。我最近一直在深入研究python的这些部分,想看看是否能学到一些新东西。tl;博士,因为我是一个笨蛋,看到了这一点,但现在我已经看到了答案。这就是我为什么问这个问题的原因。。。我经常认为没有有效/正确的方法来解决特定的问题,所以我需要回溯,直到问题以其当前形式“消失”。然而,同样经常的是,我会遇到我从未想过可能的答案,使用语言的特性或其他我根本不知道的智能。我问是否有这样的问题——我只是还不知道。这是一个很好的解决方案,但由于递归的限制,在非常大的字典上不起作用。@Tennesseleuewenburg:只有当“非常大”的意思是“占用一半的内存”或“深度接近1000”时,这两个问题都不是常见的问题。无论如何,您可以通过将其从自顶向下更改为自底向上递归来解决第一个问题,第二个问题是使用显式堆栈上的循环而不是递归,但是,对于一个你通常不会遇到的问题,任何一个都会使你的代码变得更加复杂……用python3的
项替换
iteritems
,如果你有这两个项的嵌套组合,我的意思是dict to defaultdict of dict或任何顺序,这种方法都不起作用。如果isinstance(d,defaultdict)或isinstance(d,dict),您可能需要将if条件更改为
@ShivamKThakkar:然后只需使用
if isinstance(d,dict):
defaultdict
dict
的一个子类,并且同样通过了实例测试。而
isinstance()
将一个元组作为第二个参数,如果您需要测试多个类型,而这些类型不是另一个类型的子类,则可以使用
isinstance(例如,(type1,type2,…)
。pickled
defaultdict
是否会在另一个未定义
工厂的脚本中无问题加载?我刚刚测试了(
,在一个脚本中,open(“d.pickle”,“wb”)作为fh:dump(defdick,fh)
,在另一个脚本中,open(“d.pickle”,“rb”)作为fh:defdict=load(fh)
),这会导致属性错误:无法在
上获取属性“factory”。在帮助中转换为普通的常规dict。
>>> pickle.dumps(defdict)
PicklingError: Can't pickle <function <lambda> at 0x10d7f4c80>: attribute lookup <lambda> on __main__ failed
def factory(): return defaultdict(factory)
>>> from collections import defaultdict
>>> def factory(): return defaultdict(factory)
>>> defdict = factory()
>>> defdict['one']['two']['three']['four'] = 5
>>> import pickle
>>> pickle.dumps(defdict)
b'\x80\x03ccollections\ndefaultdict\nq\x00c__main__\nfactory\nq\x01\x85q\x02Rq\x03X\x03\x00\x00\x00oneq\x04h\x00h\x01\x85q\x05Rq\x06X\x03\x00\x00\x00twoq\x07h\x00h\x01\x85q\x08Rq\tX\x05\x00\x00\x00threeq\nh\x00h\x01\x85q\x0bRq\x0cX\x04\x00\x00\x00fourq\rK\x05ssss.'