如果我想在子字典中设置变量,有没有办法动态创建缺失键。
基本上我想创建任何缺失的键并设置我的值。
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'] = []
有没有办法在一行或两行中做到这一点?
答案 0 :(得分:3)
没有递归就更容易做到:
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
答案 1 :(得分:1)
使用collections.defaultdict
self.portdict = defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: defaultdict(lambda: []))))
答案 2 :(得分:1)
我过去遇到过类似的问题。我发现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
之类的内容效果会很好。
以下是使用4个levels
和list
作为默认函数的“自动”键的示例:
>>> 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个“级别”是 switch-name,neighbor-name,local,&amp;端口 - 看起来您希望底层的list
存储您的端口。
使用2 levels
和lambda: 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})})
答案 3 :(得分:0)
仔细查看collections.defaultdict:
from collections import defaultdict
foo = defaultdict(dict)
foo['bar'] = defaultdict(dict)
foo['bar']['baz'] = defaultdict(dict)
foo['bar']['baz']['aaa'] = 1
foo['bor'] = 0
foo['bir'] = defaultdict(list)
foo['bir']['biz'].append(1)
foo['bir']['biz'].append(2)
print foo
defaultdict(<type 'dict'>, {'bir': defaultdict(<type 'list'>, {'biz': [1, 2]}), 'bor': 0, 'bar': defaultdict(<type 'dict'>, {'baz': defaultdict(<type 'dict'>, {'aaa': 1})})})