递归字典创建python

2024-09-29 23:29:44 发布

您现在位置:Python中文网/ 问答频道 /正文

如果我想在子字典中设置一个变量,有没有办法动态地创建缺少的键。你知道吗

本质上,我想创建任何缺少的键并设置我的值。你知道吗

self.portdict[switchname][str(neighbor['name'])]['local']['ports'] = []

目前我正在做,但很混乱:

if not switchname in self.portdict:
    self.portdict[switchname] = {}
if not str(neighbor['name']) in self.portdict[switchname]:
    self.portdict[switchname][str(neighbor['name'])] = {}
if not 'local' in self.portdict[switchname][str(neighbor['name'])]:
    self.portdict[switchname][str(neighbor['name'])]['local'] = {}
if not 'ports' in self.portdict[switchname][str(neighbor['name'])]['local']:
    self.portdict[switchname][str(neighbor['name'])]['local']['ports'] = []

有没有办法用一行或两行来代替呢?你知道吗


Tags: nameinselfif字典localnot动态
3条回答

我过去也遇到过类似的问题。我发现defaultdict对我来说是正确的答案,但是写超长的定义(比如@o11c的答案或@Apero的答案)并不好。我想到的是:

from collections import defaultdict
from functools import partial

def NestedDefaultDict(levels, baseFn):
    def NDD(lvl):
        return partial(defaultdict, NDD(lvl-1)) if lvl > 0 else baseFn
    return defaultdict(NDD(levels-1))

这将创建一个包含levels个嵌套字典的字典。因此,如果levels=3,则需要3个键来访问底层值。第二个参数是用于创建底层值的函数。像list或者lambda: 0或者甚至dict这样的东西都能很好地工作。你知道吗

下面是一个使用4levelslist作为默认函数的“自动”键的示例:

>>> x = NestedDefaultDict(4, list)
>>> x[1][2][3][4].append('hello')
>>> x
defaultdict(<functools.partial object at 0x10b5c22b8>, {1: defaultdict(<functools.partial object at 0x10b5c2260>, {2: defaultdict(<functools.partial object at 0x10b5c2208>, {3: defaultdict(<type 'list'>, {4: ['hello']})})})})

我想这基本上就是你想问的问题。您的4个“级别”是交换机名称、邻居名称、本地和端口——看起来您希望在底层有一个list来存储端口。你知道吗

另一个使用2 levelslambda: 0作为默认值的示例:

>>> y = NestedDefaultDict(2, lambda: 0)
>>> y['foo']['bar'] += 7
>>> y['foo']['baz'] += 10
>>> y['foo']['bar'] += 1
>>> y
defaultdict(<functools.partial object at 0x1021f1310>, {'foo': defaultdict(<function <lambda> at 0x1021f3938>, {'baz': 10, 'bar': 8})})

使用collections.defaultdict

self.portdict = defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: []))))

这在没有递归的情况下更容易做到:

def set_by_path(dct, path, value):
    ipath = iter(path)
    p_last = next(ipath)
    try:
        while True:
            p_next = next(ipath)
            dct = dct.setdefault(p_last, {})
            p_last = p_next
    except StopIteration:
        dct[p_last] = value

以及一个测试用例:

d = {}
set_by_path(d, ['foo', 'bar', 'baz'], 'qux')
print d  # {'foo': {'bar': {'baz': 'qux'}}}

如果您想拥有它,因此不需要函数,可以使用以下defaultdict工厂,它允许您任意深入地嵌套内容:

from collections import defaultdict

defaultdict_factory = lambda : defaultdict(defaultdict_factory)

d = defaultdict_factory()
d['foo']['bar']['baz'] = 'qux'
print d

相关问题 更多 >

    热门问题