我需要创建一个 json 文件,给定路径及其值的字典。我编写了一些用于添加条目的代码,看起来它的功能并且结果是正确的,但是作为 python 新手,我想知道如何改进这一点,并且是否有一个功能相同的功能已经存在于模块中包含在 python 2.7 中吗?
def path_to_list(path):
if isinstance(path, (str,)):
map_list = path.split("/")
for i, key in enumerate(map_list):
if key.isdigit():
map_list[i] = int(key)
else:
map_list = path
return map_list
def add_to_dictionary(dic, keys, value):
for i, key in enumerate(keys[:-1]):
if i < len(keys)-1 and isinstance(keys[i+1], int):
# Case where current key should be a list, since next key is
# is list position
if key not in dic.keys():
# Case list not yet exist
dic[keys[i]] = []
dic[keys[i]].append({})
dic = dic.setdefault(key, {})
elif not isinstance(dic[key], list):
# Case key exist , but not a list
# TO DO : check how to handle
print "Failed to insert " + str(keys) + ", trying to insert multiple to not multiple "
break
else:
# Case where the list exist
dic = dic.setdefault(key, {})
elif i < len(keys)-1 and isinstance(key, int):
# Case where current key is instance number in a list
try:
# If this succeeds instance already exist
dic = dic[key]
except (IndexError,KeyError):
# Case where list exist , but need to add new instances ,
# as key instance not exist
while len(dic)-1 < key:
dic.append({})
dic = dic[key]
else:
# Case where key is not list or instance of list
dic = dic.setdefault(key, {})
# Update value
dic[keys[-1]] = value
my_dict1 ={}
add_to_dictionary(my_dict1, path_to_list("a/0/b/c"), 1)
print my_dict1
{'a': [{'b': {'c': 1}}]}
add_to_dictionary(my_dict1, path_to_list("a/2/b/c"), "string")
print my_dict1
{'a': [{'b': {'c': 1}}, {}, {'b': {'c': 'string'}}]}
add_to_dictionary(my_dict1, path_to_list("a/2/b/c"), "new string")
print my_dict1
{'a': [{'b': {'c': 1}}, {}, {'b': {'c': 'new string'}}]}
某些键可能已经存在,然后我只更新值。
数字键表示该键之前可以有多个值,我正在数组中的这个位置添加/更新值
最佳答案
这是我使用嵌套字典实现的数据结构:
class Tree(dict):
'''http://stackoverflow.com/questions/635483/what-is-the-best-way-to-implement-nested-dictionaries-in-python'''
def __missing__(d, k):
v = d[k] = type(d)()
return v
def grow(d, path, v):
ps = map(lambda k: int(k) if k.isdigit() else k, path.split('/'))
reduce(lambda d, k: d[k], ps[:-1], d)[ps[-1]] = v
测试一下:
t = Tree()
t.grow('a/0/b/c', 1)
print t
t['a'][2]['b']['c'] = 'string'
print t
t.grow('a/2/b/c', 'new_string')
print t
给出:
{'a': {0: {'b': {'c': 1}}}}
{'a': {0: {'b': {'c': 1}}, 2: {'b': {'c': 'string'}}}}
{'a': {0: {'b': {'c': 1}}, 2: {'b': {'c': 'new_string'}}}}
但是您希望整数索引字典是数组。下面的例程逐步遍历嵌套字典,将其中一些字典转换为列表。它会进行一些复制,以免弄乱原始的嵌套字典。我只会将其用作输出阶段的一部分。
import numbers
def keys_all_int(d):
return reduce(lambda r, k: r and isinstance(k, numbers.Integral), d.keys(), True)
def listify(d):
'''
Take a tree of nested dictionaries, and
return a copy of the tree with sparse lists in place of the dictionaries
that had only integers as keys.
'''
if isinstance(d, dict):
d = d.copy()
for k in d:
d[k] = listify(d[k])
if keys_all_int(d):
ds = [{}]*(max(d.keys())+1)
for k in d:
ds[k] = d[k]
return ds
return d
测试一下:
t = Tree()
t.grow('a/0/b/c', 1)
print listify(t)
t['a'][2]['b']['c'] = 'string'
print listify(t)
t.grow('a/2/b/c', 'new_string')
print listify(t)
给予:
{'a': [{'b': {'c': 1}}]}
{'a': [{'b': {'c': 1}}, {}, {'b': {'c': 'string'}}]}
{'a': [{'b': {'c': 1}}, {}, {'b': {'c': 'new_string'}}]}
最后,如果您要处理 JSON,请使用 json
模块:
import json
print json.dumps(listify(t),
sort_keys=True, indent = 4, separators = (',', ': '))
给予:
{
"a": [
{
"b": {
"c": 1
}
},
{},
{
"b": {
"c": "new_string"
}
}
]
}
关于python - 在python中,如何最好地插入给定变量路径和值的键:value to json,,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55371617/