还原为任意嵌套字典需要您为任意路径创建新字典; c__d 表示必须有一个与c 键关联的嵌套字典,因此您可以在其中设置d。 c__d__e 表示 c 是一个字典,其中 d 键指向另一个字典,是否设置了 e 等等。基本上,除了 key.split('__') 中的最后一个元素之外的所有内容都是字典中指向另一个字典的键字典,如果这些字典尚未创建,则需要循环创建它们。
您可以使用functools.reduce() 来执行此操作,有关get_nested_default() 和set_nested() 函数的说明,请参阅this previous answer of mine:
from functools import reduce
def get_nested_default(d, path):
return reduce(lambda d, k: d.setdefault(k, {}), path, d)
def set_nested(d, path, value):
get_nested_default(d, path[:-1])[path[-1]] = value
def unflatten(d, separator='__'):
output = {}
for k, v in d.items():
path = k.split(separator)
set_nested(output, path, v)
return output
get_nested_default() 负责为任意数量的键创建那些尚不存在的嵌套字典。 set_nested() 负责将路径中的最后一个键与其余键分开,并在最里面的字典中设置值。
当然,这假设输入最初从未在键中使用__。但是,只要您选择一个不用作输入字典中任何键的子字符串的路径分隔符,您就可以将其还原为原始形式。
关于您的示例的演示:
>>> unflatten({'a': 'b', 'c__d': 'g'})
{'a': 'b', 'c': {'d': 'g'}}
还有一个使用不同分隔符的更复杂的:
>>> from pprint import pprint
>>> flat = {
... 'foo::bar::baz': 'Eric Idle',
... 'foo::bar::spam': 'John Cleese',
... 'foo::spam::ham': 'Terry Gilliam',
... 'spam::ham': 'Vikings singing'
... }
>>> nested = unflatten(flat, '::')
>>> pprint(nested)
{'foo': {'bar': {'baz': 'Eric Idle', 'spam': 'John Cleese'},
'spam': {'ham': 'Terry Gilliam'}},
'spam': {'ham': 'Vikings singing'}}