Python 如何通过字典递归并动态更新值,以便以后可以引用它们?
我正在尝试编写一个配置变量引擎,该引擎接受YAML文件(包含AWS配置变量)作为输入,并将其转换为JSON,以便可以将其上载到HTTP k/v API(如concur)。一个让我感到困惑的特性将允许开发人员在后续的键中“包括”键集(用下划线标识,在最终有效负载中省略)。示例如下:Python 如何通过字典递归并动态更新值,以便以后可以引用它们?,python,json,dictionary,recursion,yaml,Python,Json,Dictionary,Recursion,Yaml,我正在尝试编写一个配置变量引擎,该引擎接受YAML文件(包含AWS配置变量)作为输入,并将其转换为JSON,以便可以将其上载到HTTP k/v API(如concur)。一个让我感到困惑的特性将允许开发人员在后续的键中“包括”键集(用下划线标识,在最终有效负载中省略)。示例如下: # Region us-east-1: # Any key preceded by an underscore (_) is considered a "tag group" and will not be upl
# Region
us-east-1:
# Any key preceded by an underscore (_) is considered a "tag group" and will not be uploaded to Consul KV unless explicitly included.
_taggroup1:
key1: value1
key2: value2
key3: value3
_taggroup2:
key4: value1
key5: value2
key6: value3
dev:
_include: us-east-1/_taggroup1
qa:
_include:
- us-east-1/_taggroup1
- us-east-1/_taggroup2
key6: baz
prod:
_include:
- us-east-1/_taggroup1
- us-east-1/_taggroup2
us-west-1:
_taggroup1:
key1: value1
key2: value2
key3: value3
_taggroup2:
key4: value1
key5: value2
key6: value3
dev:
_include:
- us-west-1/_taggroup1
qa:
_include:
- us-west-1/_taggroup1
- us-west-1/_taggroup2
key2: foo
prod:
_include:
- us-west-1/_taggroup1
- us-west-1/_taggroup2
key4: foo
key5: bar
key1: undef
us-west-1a:
qa:
_include: us-west-1/qa
prod:
_include: us-west-1/prod
us-west-1b:
_include: us-west-1/us-west-1a
如您所见,我正在尝试构造一个配置文件,允许开发人员对变量进行分组,并在他们愿意的情况下包含/覆盖它们
到目前为止,我为本实验编写的代码基本上是您的标准递归函数,其中添加了特定于此应用程序的内容:
# parse_input is a separate function that converts a YAML stream into
# an OrderedDict
original_dict = parse_input(stream1)
def print_dict(input_dict):
new_dict = collections.OrderedDict()
for key, value in input_dict.iteritems():
if key.startswith('_'):
if key == '_include':
if isinstance(value, list):
for item in value:
x = dpath.util.get(original_dict, item)
for k, v in x.iteritems():
new_dict[k] = v
else:
x = dpath.util.get(original_dict, value)
for k, v in x.iteritems():
new_dict[k] = v
else:
continue
continue
elif isinstance(value, dict):
new_dict[key] = print_dict(value)
else:
new_dict[key] = value
return new_dict
到目前为止,我取得的成果如下:
{
"us-east-1": {
"dev": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
},
"qa": {
"key1": "value1",
"key2": "value2",
"key3": "value3",
"key4": "value1",
"key5": "value2",
"key6": "baz"
},
"prod": {
"key1": "value1",
"key2": "value2",
"key3": "value3",
"key4": "value1",
"key5": "value2",
"key6": "value3"
}
},
"us-west-1": {
"dev": {
"key1": "value1",
"key2": "value2",
"key3": "value3"
},
"qa": {
"key1": "value1",
"key2": "foo",
"key3": "value3",
"key4": "value1",
"key5": "value2",
"key6": "value3"
},
"prod": {
"key1": "undef",
"key2": "value2",
"key3": "value3",
"key4": "foo",
"key5": "bar",
"key6": "value3"
},
"us-west-1a": {
"qa": {
"_include": [
"us-west-1/_taggroup1",
"us-west-1/_taggroup2"
],
"key2": "foo"
},
"prod": {
"_include": [
"us-west-1/_taggroup1",
"us-west-1/_taggroup2"
],
"key4": "foo",
"key5": "bar",
"key1": "undef"
}
},
"us-west-1b": {
"qa": {
"_include": "us-west-1/qa"
},
"prod": {
"_include": "us-west-1/prod"
}
}
}
}
正如你所看到的,我似乎已经到了一半。我的问题是,在最初的实验中,我在引用包含集时引用函数中的original_dict
变量(使用dpath
返回键),得到了良好的结果。这很快就会变成一个问题,因为函数递归更深(即,在本例中是AZ特定变量),因为我不知道如何动态更新原始dict中的键,或者以其他方式跟踪更改,因此函数将注入一个带有\u include
键的键集,并且无法重新计算它们
我如何消除依赖于引用原始词典的情况,而是动态跟踪更改,以便在树的更深处正确地计算
\u include
键?我认为此代码解决了您所面临的问题。关键的变化是递归到print_dict
,结果来自dpath
。我还折叠了一些冗余代码
代码:
import yaml
import collections
import json
import dpath
with open('data.yml', 'rb') as f:
original_dict = yaml.load(f)
def print_dict(input_dict):
new_dict = collections.OrderedDict()
for key, value in input_dict.iteritems():
if key.startswith('_'):
if key == '_include':
if not isinstance(value, list):
value = [value]
for item in value:
x = print_dict(dpath.util.get(original_dict, item))
for k, v in x.iteritems():
new_dict[k] = v
elif isinstance(value, dict):
new_dict[key] = print_dict(value)
else:
new_dict[key] = value
return new_dict
print(json.dumps(print_dict(original_dict), indent=2))
{
"us-east-1": {
"qa": {
"key3": "value3",
"key2": "value2",
"key1": "value1",
"key6": "baz",
"key5": "value2",
"key4": "value1"
},
"prod": {
"key3": "value3",
"key2": "value2",
"key1": "value1",
"key6": "value3",
"key5": "value2",
"key4": "value1"
},
"dev": {
"key3": "value3",
"key2": "value2",
"key1": "value1"
}
},
"us-west-1": {
"qa": {
"key2": "value2",
"key3": "value3",
"key1": "value1",
"key6": "value3",
"key5": "value2",
"key4": "value1"
},
"us-west-1b": {
"qa": {
"key2": "value2",
"key3": "value3",
"key1": "value1",
"key6": "value3",
"key5": "value2",
"key4": "value1"
},
"prod": {
"key1": "value1",
"key3": "value3",
"key2": "value2",
"key6": "value3",
"key5": "bar",
"key4": "foo"
}
},
"prod": {
"key1": "value1",
"key3": "value3",
"key2": "value2",
"key6": "value3",
"key5": "bar",
"key4": "foo"
},
"us-west-1a": {
"qa": {
"key2": "value2",
"key3": "value3",
"key1": "value1",
"key6": "value3",
"key5": "value2",
"key4": "value1"
},
"prod": {
"key1": "value1",
"key3": "value3",
"key2": "value2",
"key6": "value3",
"key5": "bar",
"key4": "foo"
}
},
"dev": {
"key3": "value3",
"key2": "value2",
"key1": "value1"
}
}
}
输出:
import yaml
import collections
import json
import dpath
with open('data.yml', 'rb') as f:
original_dict = yaml.load(f)
def print_dict(input_dict):
new_dict = collections.OrderedDict()
for key, value in input_dict.iteritems():
if key.startswith('_'):
if key == '_include':
if not isinstance(value, list):
value = [value]
for item in value:
x = print_dict(dpath.util.get(original_dict, item))
for k, v in x.iteritems():
new_dict[k] = v
elif isinstance(value, dict):
new_dict[key] = print_dict(value)
else:
new_dict[key] = value
return new_dict
print(json.dumps(print_dict(original_dict), indent=2))
{
"us-east-1": {
"qa": {
"key3": "value3",
"key2": "value2",
"key1": "value1",
"key6": "baz",
"key5": "value2",
"key4": "value1"
},
"prod": {
"key3": "value3",
"key2": "value2",
"key1": "value1",
"key6": "value3",
"key5": "value2",
"key4": "value1"
},
"dev": {
"key3": "value3",
"key2": "value2",
"key1": "value1"
}
},
"us-west-1": {
"qa": {
"key2": "value2",
"key3": "value3",
"key1": "value1",
"key6": "value3",
"key5": "value2",
"key4": "value1"
},
"us-west-1b": {
"qa": {
"key2": "value2",
"key3": "value3",
"key1": "value1",
"key6": "value3",
"key5": "value2",
"key4": "value1"
},
"prod": {
"key1": "value1",
"key3": "value3",
"key2": "value2",
"key6": "value3",
"key5": "bar",
"key4": "foo"
}
},
"prod": {
"key1": "value1",
"key3": "value3",
"key2": "value2",
"key6": "value3",
"key5": "bar",
"key4": "foo"
},
"us-west-1a": {
"qa": {
"key2": "value2",
"key3": "value3",
"key1": "value1",
"key6": "value3",
"key5": "value2",
"key4": "value1"
},
"prod": {
"key1": "value1",
"key3": "value3",
"key2": "value2",
"key6": "value3",
"key5": "bar",
"key4": "foo"
}
},
"dev": {
"key3": "value3",
"key2": "value2",
"key1": "value1"
}
}
}
这似乎有效!谢谢,我(显然)还没有试过!:)