我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?
try:
example_dict['key1']['key2']
except KeyError:
pass
或者python有一个类似get()的方法用于嵌套字典?
我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?
try:
example_dict['key1']['key2']
except KeyError:
pass
或者python有一个类似get()的方法用于嵌套字典?
当前回答
从Python 3.4开始,你可以使用suppress (KeyError)来访问嵌套的json对象,而不用担心KeyError
from contextlib import suppress
with suppress(KeyError):
a1 = json_obj['key1']['key2']['key3']
a2 = json_obj['key4']['key5']['key6']
a3 = json_obj['key7']['key8']['key9']
Techdragon提供。看看他的回答,了解更多细节:https://stackoverflow.com/a/45874251/1189659
其他回答
还有一个相同功能的函数,也返回一个布尔值来表示是否找到键,并处理一些意想不到的错误。
'''
json : json to extract value from if exists
path : details.detail.first_name
empty path represents root
returns a tuple (boolean, object)
boolean : True if path exists, otherwise False
object : the object if path exists otherwise None
'''
def get_json_value_at_path(json, path=None, default=None):
if not bool(path):
return True, json
if type(json) is not dict :
raise ValueError(f'json={json}, path={path} not supported, json must be a dict')
if type(path) is not str and type(path) is not list:
raise ValueError(f'path format {path} not supported, path can be a list of strings like [x,y,z] or a string like x.y.z')
if type(path) is str:
path = path.strip('.').split('.')
key = path[0]
if key in json.keys():
return get_json_value_at_path(json[key], path[1:], default)
else:
return False, default
使用示例:
my_json = {'details' : {'first_name' : 'holla', 'last_name' : 'holla'}}
print(get_json_value_at_path(my_json, 'details.first_name', ''))
print(get_json_value_at_path(my_json, 'details.phone', ''))
(真的,大声叫) (假的,”)
虽然reduce方法简洁而简短,但我认为简单的循环更容易理解。我还包含了一个默认参数。
def deep_get(_dict, keys, default=None):
for key in keys:
if isinstance(_dict, dict):
_dict = _dict.get(key, default)
else:
return default
return _dict
作为理解reduce一行程序如何工作的练习,我执行了以下操作。但最终循环方法对我来说似乎更直观。
def deep_get(_dict, keys, default=None):
def _reducer(d, key):
if isinstance(d, dict):
return d.get(key, default)
return default
return reduce(_reducer, keys, _dict)
使用
nested = {'a': {'b': {'c': 42}}}
print deep_get(nested, ['a', 'b'])
print deep_get(nested, ['a', 'b', 'z', 'z'], default='missing')
我建议你试试蟒蛇本尼迪克特。
它是一个dict子类,提供小键盘支持等功能。
安装:pip install python-benedict
from benedict import benedict
example_dict = benedict(example_dict, keypath_separator='.')
现在你可以使用keypath访问嵌套值:
val = example_dict['key1.key2']
# using 'get' method to avoid a possible KeyError:
val = example_dict.get('key1.key2')
或者使用键列表访问嵌套值:
val = example_dict['key1', 'key2']
# using get to avoid a possible KeyError:
val = example_dict.get(['key1', 'key2'])
它在GitHub上经过了很好的测试和开源:
https://github.com/fabiocaccamo/python-benedict
注:我是这个项目的作者
一个简单的类,可以包装字典,并根据键进行检索:
class FindKey(dict):
def get(self, path, default=None):
keys = path.split(".")
val = None
for key in keys:
if val:
if isinstance(val, list):
val = [v.get(key, default) if v else None for v in val]
else:
val = val.get(key, default)
else:
val = dict.get(self, key, default)
if not val:
break
return val
例如:
person = {'person':{'name':{'first':'John'}}}
FindDict(person).get('person.name.first') # == 'John'
如果该键不存在,则默认返回None。你可以在FindDict包装器中使用default=键覆盖它,例如':
FindDict(person, default='').get('person.name.last') # == doesn't exist, so ''
递归解。它不是最有效的,但我发现它比其他示例更具可读性,而且它不依赖于functools。
def deep_get(d, keys):
if not keys or d is None:
return d
return deep_get(d.get(keys[0]), keys[1:])
例子
d = {'meta': {'status': 'OK', 'status_code': 200}}
deep_get(d, ['meta', 'status_code']) # => 200
deep_get(d, ['garbage', 'status_code']) # => None
一个更精致的版本
def deep_get(d, keys, default=None):
"""
Example:
d = {'meta': {'status': 'OK', 'status_code': 200}}
deep_get(d, ['meta', 'status_code']) # => 200
deep_get(d, ['garbage', 'status_code']) # => None
deep_get(d, ['meta', 'garbage'], default='-') # => '-'
"""
assert type(keys) is list
if d is None:
return default
if not keys:
return d
return deep_get(d.get(keys[0]), keys[1:], default)