我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?
try:
example_dict['key1']['key2']
except KeyError:
pass
或者python有一个类似get()的方法用于嵌套字典?
我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?
try:
example_dict['key1']['key2']
except KeyError:
pass
或者python有一个类似get()的方法用于嵌套字典?
当前回答
一个简单的类,可以包装字典,并根据键进行检索:
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 ''
其他回答
如果您想使用另一个库来解决问题,这是最好的方法
https://github.com/maztohir/dict-path
from dict-path import DictPath
data_dict = {
"foo1": "bar1",
"foo2": "bar2",
"foo3": {
"foo4": "bar4",
"foo5": {
"foo6": "bar6",
"foo7": "bar7",
},
}
}
data_dict_path = DictPath(data_dict)
data_dict_path.get('key1/key2/key3')
已经有很多很好的答案,但我已经提出了一个类似于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
根据Yoav的回答,一个更安全的方法是:
def deep_get(dictionary, *keys):
return reduce(lambda d, key: d.get(key, None) if isinstance(d, dict) else None, keys, dictionary)
对于嵌套的字典/JSON查找,可以使用dictor
PIP安装指示器
dict对象
{
"characters": {
"Lonestar": {
"id": 55923,
"role": "renegade",
"items": [
"space winnebago",
"leather jacket"
]
},
"Barfolomew": {
"id": 55924,
"role": "mawg",
"items": [
"peanut butter jar",
"waggy tail"
]
},
"Dark Helmet": {
"id": 99999,
"role": "Good is dumb",
"items": [
"Shwartz",
"helmet"
]
},
"Skroob": {
"id": 12345,
"role": "Spaceballs CEO",
"items": [
"luggage"
]
}
}
}
要获得龙星的物品,只需提供一个点分隔的路径,即
import json
from dictor import dictor
with open('test.json') as data:
data = json.load(data)
print dictor(data, 'characters.Lonestar.items')
>> [u'space winnebago', u'leather jacket']
如果键不在路径中,您可以提供回退值
你还有很多选择,比如忽略字母大小写,使用'以外的其他字符。作为路径分隔符,
https://github.com/perfecto25/dictor
我已经编写了一个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