我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?
try:
example_dict['key1']['key2']
except KeyError:
pass
或者python有一个类似get()的方法用于嵌套字典?
我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?
try:
example_dict['key1']['key2']
except KeyError:
pass
或者python有一个类似get()的方法用于嵌套字典?
当前回答
对于二级键检索,你可以这样做:
key2_value = (example_dict.get('key1') or {}).get('key2')
其他回答
你可以使用get两次:
example_dict.get('key1', {}).get('key2')
如果key1或key2不存在,则返回None。
注意,如果example_dict['key1']存在但不是dict(或具有get方法的类dict对象),仍然可能引发AttributeError。如果example_dict['key1']不可下标,你发布的try..except代码将引发TypeError。
另一个区别是try…除非在第一次丢失钥匙后立即发生短路。get调用链则不然。
如果您希望保留语法example_dict['key1']['key2'],但不希望它引发KeyErrors,那么您可以使用哈希recipe:
class Hasher(dict):
# https://stackoverflow.com/a/3405143/190597
def __missing__(self, key):
value = self[key] = type(self)()
return value
example_dict = Hasher()
print(example_dict['key1'])
# {}
print(example_dict['key1']['key2'])
# {}
print(type(example_dict['key1']['key2']))
# <class '__main__.Hasher'>
注意,当缺少一个键时,返回一个空的hash。
因为Hasher是dict的一个子类,你可以像使用dict一样使用Hasher。所有相同的方法和语法都是可用的,哈希器只是以不同的方式对待缺失的键。
你可以像这样把一个普通字典转换成哈希:
hasher = Hasher(example_dict)
并将哈希转换为普通字典一样容易:
regular_dict = dict(hasher)
另一种选择是在helper函数中隐藏丑陋的代码:
def safeget(dct, *keys):
for key in keys:
try:
dct = dct[key]
except KeyError:
return None
return dct
这样你剩下的代码就可以保持相对的可读性:
safeget(example_dict, 'key1', 'key2')
还有一个相同功能的函数,也返回一个布尔值来表示是否找到键,并处理一些意想不到的错误。
'''
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', ''))
(真的,大声叫) (假的,”)
你可以用虚线:
PIP安装
from dotted.collection import DottedDict
assert DottedDict(dict(foo=dict(bar="baz")))["foo"]["bar"] == "baz"
assert DottedDict(dict(foo=dict(bar="baz")))["foo.bar"] == "baz"
assert DottedDict(dict(foo=dict(bar="baz"))).get("lorem.ipsum", None) is None
assert DottedDict(dict(foo=dict(bar="baz"))).get("lorem.ipsum", "default") == "default"
我已经编写了一个deepextract包,它完全符合您的要求:https://github.com/ya332/deepextract 你可以这样做
from deepextract import deepextract
# Demo: deepextract.extract_key(obj, key)
deeply_nested_dict = {
"items": {
"item": {
"id": {
"type": {
"donut": {
"name": {
"batters": {
"my_target_key": "my_target_value"
}
}
}
}
}
}
}
}
print(deepextract.extract_key(deeply_nested_dict, "my_target_key") == "my_target_value")
返回
True
已经有很多很好的答案,但我已经提出了一个类似于JavaScript领域的lodash get的函数,它也支持通过索引进入列表:
def get(value, keys, default_value = None):
'''
Useful for reaching into nested JSON like data
Inspired by JavaScript lodash get and Clojure get-in etc.
'''
if value is None or keys is None:
return None
path = keys.split('.') if isinstance(keys, str) else keys
result = value
def valid_index(key):
return re.match('^([1-9][0-9]*|[0-9])$', key) and int(key) >= 0
def is_dict_like(v):
return hasattr(v, '__getitem__') and hasattr(v, '__contains__')
for key in path:
if isinstance(result, list) and valid_index(key) and int(key) < len(result):
result = result[int(key)] if int(key) < len(result) else None
elif is_dict_like(result) and key in result:
result = result[key]
else:
result = default_value
break
return result
def test_get():
assert get(None, ['foo']) == None
assert get({'foo': 1}, None) == None
assert get(None, None) == None
assert get({'foo': 1}, []) == {'foo': 1}
assert get({'foo': 1}, ['foo']) == 1
assert get({'foo': 1}, ['bar']) == None
assert get({'foo': 1}, ['bar'], 'the default') == 'the default'
assert get({'foo': {'bar': 'hello'}}, ['foo', 'bar']) == 'hello'
assert get({'foo': {'bar': 'hello'}}, 'foo.bar') == 'hello'
assert get({'foo': [{'bar': 'hello'}]}, 'foo.0.bar') == 'hello'
assert get({'foo': [{'bar': 'hello'}]}, 'foo.1') == None
assert get({'foo': [{'bar': 'hello'}]}, 'foo.1.bar') == None
assert get(['foo', 'bar'], '1') == 'bar'
assert get(['foo', 'bar'], '2') == None