根据条件递归地将键添加到嵌套字典
Add key to the nested dictionary recursively based on condition
我有一个多级嵌套字典,试图在该字典中有 type
键时添加一个键 required
。
代码:
def add_recursively(val):
if 'type' in val and val['type'] != 'object':
val['required'] = False
return val
elif 'type' in val and val['type'] == 'object' and 'object_schema' in val:
return add_recursively(val['object_schema'])
else:
val['required'] = False
return val
new_data = {}
for key, value in data.items():
if value['type'] == 'object' and 'object_schema' in value:
new_data[key] = add_recursively(value)
else:
value['required'] = False
new_data[key] = value
输入数据:
data = {'key1': {'description': 'Configuration for OpenID', 'type': 'boolean'},
'key2': {'default': {'enabled': True, 'logging_percent': 100},
'object_schema': {'enabled': {'default': True, 'type': 'boolean'},
'logging_percent': {'default': 100, 'type': 'float'},
'nested_key': {'default': {'new_enable': True, 'new_precent': 100},
'object_schema': {'new_enable': {'default': True, 'type': 'boolean'},
'new_precent': {'default': 100, 'type': 'float'}},
'type': 'object'}},
'type': 'object'}}
输出数据:
{'key1': {'description': 'Configuration for OpenID',
'required': False,
'type': 'boolean'},
'key2': {'enabled': {'default': True, 'type': 'boolean'},
'logging_percent': {'default': 100, 'type': 'float'},
'nested_key': {'default': {'new_enable': True, 'new_precent': 100},
'object_schema': {'new_enable': {'default': True, 'type': 'boolean'},
'new_precent': {'default': 100, 'type': 'float'}},
'type': 'object'},
'required': False}}
预期输出:
{'key1': {
'required': False,
'description': 'Configuration for OpenID',
'type': 'boolean'},
'key2': {
'required': False,
'enabled': {'required': False, 'default': True, 'type': 'boolean'},
'logging_percent': {'required': False, 'default': 100, 'type': 'float'},
'nested_key': {'default': {'new_enable': True, 'new_precent': 100},
'object_schema': {'new_enable': {'required': False, 'default': True, 'type': 'boolean'},
'new_precent': {'required': False, 'default': 100, 'type': 'float'}},
'type': 'object'},
}}
这是修改 data
in-place 的一种方法,方法是向每个包含 type
键的键添加 required
键:
def add_required(d):
if 'type' in d:
d['required'] = False
for v in d.values():
if isinstance(v, dict):
add_required(v)
add_required(data)
输出:
>>> data
{'key1': {'description': 'Configuration for OpenID',
'type': 'boolean',
'required': False},
'key2': {'default': {'enabled': True, 'logging_percent': 100},
'object_schema': {'enabled': {'default': True,
'type': 'boolean',
'required': False},
'logging_percent': {'default': 100, 'type': 'float', 'required': False},
'nested_key': {'default': {'new_enable': True, 'new_precent': 100},
'object_schema': {'new_enable': {'default': True,
'type': 'boolean',
'required': False},
'new_precent': {'default': 100, 'type': 'float', 'required': False}},
'type': 'object',
'required': False}},
'type': 'object',
'required': False}}
有多种方法可以解决这个问题(每种方法都有自己的优点和缺点),这里是创建(嵌套)对象的副本的方法。
code00.py:
#!/usr/bin/env python
import sys
from pprint import pprint as pp
data = {
"key1": {"description": "Configuration for OpenID", "type": "boolean"},
"key2": {
"default": {
"enabled": True, "logging_percent": 100,
},
"object_schema": {
"enabled": {"default": True, "type": "boolean"},
"logging_percent": {"default": 100, "type": "float"},
"nested_key": {
"default": {"new_enable": True, "new_precent": 100},
"object_schema": {
"new_enable": {"default": True, "type": "boolean"},
"new_precent": {"default": 100, "type": "float"},
},
"type": "object",
}
},
"type": "object",
}
}
def add_rec(orig_data, new_items):
ret = {}
for k, v in orig_data.items():
if k == "type":
ret.update(new_items)
if isinstance(v, dict):
ret[k] = add_rec(v, new_items)
else:
ret[k] = v
return ret
def main(*argv):
new_data = add_rec(data, {"required": False})
pp(new_data)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
输出:
cfati@CFATI-5510-0:e:\Work\Dev\Whosebug\q072213710]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" code00.py
Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32
{'key1': {'description': 'Configuration for OpenID',
'required': False,
'type': 'boolean'},
'key2': {'default': {'enabled': True, 'logging_percent': 100},
'object_schema': {'enabled': {'default': True,
'required': False,
'type': 'boolean'},
'logging_percent': {'default': 100,
'required': False,
'type': 'float'},
'nested_key': {'default': {'new_enable': True,
'new_precent': 100},
'object_schema': {'new_enable': {'default': True,
'required': False,
'type': 'boolean'},
'new_precent': {'default': 100,
'required': False,
'type': 'float'}},
'required': False,
'type': 'object'}},
'required': False,
'type': 'object'}}
Done.
我有一个多级嵌套字典,试图在该字典中有 type
键时添加一个键 required
。
代码:
def add_recursively(val):
if 'type' in val and val['type'] != 'object':
val['required'] = False
return val
elif 'type' in val and val['type'] == 'object' and 'object_schema' in val:
return add_recursively(val['object_schema'])
else:
val['required'] = False
return val
new_data = {}
for key, value in data.items():
if value['type'] == 'object' and 'object_schema' in value:
new_data[key] = add_recursively(value)
else:
value['required'] = False
new_data[key] = value
输入数据:
data = {'key1': {'description': 'Configuration for OpenID', 'type': 'boolean'},
'key2': {'default': {'enabled': True, 'logging_percent': 100},
'object_schema': {'enabled': {'default': True, 'type': 'boolean'},
'logging_percent': {'default': 100, 'type': 'float'},
'nested_key': {'default': {'new_enable': True, 'new_precent': 100},
'object_schema': {'new_enable': {'default': True, 'type': 'boolean'},
'new_precent': {'default': 100, 'type': 'float'}},
'type': 'object'}},
'type': 'object'}}
输出数据:
{'key1': {'description': 'Configuration for OpenID',
'required': False,
'type': 'boolean'},
'key2': {'enabled': {'default': True, 'type': 'boolean'},
'logging_percent': {'default': 100, 'type': 'float'},
'nested_key': {'default': {'new_enable': True, 'new_precent': 100},
'object_schema': {'new_enable': {'default': True, 'type': 'boolean'},
'new_precent': {'default': 100, 'type': 'float'}},
'type': 'object'},
'required': False}}
预期输出:
{'key1': {
'required': False,
'description': 'Configuration for OpenID',
'type': 'boolean'},
'key2': {
'required': False,
'enabled': {'required': False, 'default': True, 'type': 'boolean'},
'logging_percent': {'required': False, 'default': 100, 'type': 'float'},
'nested_key': {'default': {'new_enable': True, 'new_precent': 100},
'object_schema': {'new_enable': {'required': False, 'default': True, 'type': 'boolean'},
'new_precent': {'required': False, 'default': 100, 'type': 'float'}},
'type': 'object'},
}}
这是修改 data
in-place 的一种方法,方法是向每个包含 type
键的键添加 required
键:
def add_required(d):
if 'type' in d:
d['required'] = False
for v in d.values():
if isinstance(v, dict):
add_required(v)
add_required(data)
输出:
>>> data
{'key1': {'description': 'Configuration for OpenID',
'type': 'boolean',
'required': False},
'key2': {'default': {'enabled': True, 'logging_percent': 100},
'object_schema': {'enabled': {'default': True,
'type': 'boolean',
'required': False},
'logging_percent': {'default': 100, 'type': 'float', 'required': False},
'nested_key': {'default': {'new_enable': True, 'new_precent': 100},
'object_schema': {'new_enable': {'default': True,
'type': 'boolean',
'required': False},
'new_precent': {'default': 100, 'type': 'float', 'required': False}},
'type': 'object',
'required': False}},
'type': 'object',
'required': False}}
有多种方法可以解决这个问题(每种方法都有自己的优点和缺点),这里是创建(嵌套)对象的副本的方法。
code00.py:
#!/usr/bin/env python
import sys
from pprint import pprint as pp
data = {
"key1": {"description": "Configuration for OpenID", "type": "boolean"},
"key2": {
"default": {
"enabled": True, "logging_percent": 100,
},
"object_schema": {
"enabled": {"default": True, "type": "boolean"},
"logging_percent": {"default": 100, "type": "float"},
"nested_key": {
"default": {"new_enable": True, "new_precent": 100},
"object_schema": {
"new_enable": {"default": True, "type": "boolean"},
"new_precent": {"default": 100, "type": "float"},
},
"type": "object",
}
},
"type": "object",
}
}
def add_rec(orig_data, new_items):
ret = {}
for k, v in orig_data.items():
if k == "type":
ret.update(new_items)
if isinstance(v, dict):
ret[k] = add_rec(v, new_items)
else:
ret[k] = v
return ret
def main(*argv):
new_data = add_rec(data, {"required": False})
pp(new_data)
if __name__ == "__main__":
print("Python {:s} {:03d}bit on {:s}\n".format(" ".join(elem.strip() for elem in sys.version.split("\n")),
64 if sys.maxsize > 0x100000000 else 32, sys.platform))
rc = main(*sys.argv[1:])
print("\nDone.")
sys.exit(rc)
输出:
cfati@CFATI-5510-0:e:\Work\Dev\Whosebug\q072213710]> "e:\Work\Dev\VEnvs\py_pc064_03.09_test0\Scripts\python.exe" code00.py Python 3.9.9 (tags/v3.9.9:ccb0e6a, Nov 15 2021, 18:08:50) [MSC v.1929 64 bit (AMD64)] 064bit on win32 {'key1': {'description': 'Configuration for OpenID', 'required': False, 'type': 'boolean'}, 'key2': {'default': {'enabled': True, 'logging_percent': 100}, 'object_schema': {'enabled': {'default': True, 'required': False, 'type': 'boolean'}, 'logging_percent': {'default': 100, 'required': False, 'type': 'float'}, 'nested_key': {'default': {'new_enable': True, 'new_precent': 100}, 'object_schema': {'new_enable': {'default': True, 'required': False, 'type': 'boolean'}, 'new_precent': {'default': 100, 'required': False, 'type': 'float'}}, 'required': False, 'type': 'object'}}, 'required': False, 'type': 'object'}} Done.