我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?
try:
example_dict['key1']['key2']
except KeyError:
pass
或者python有一个类似get()的方法用于嵌套字典?
我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?
try:
example_dict['key1']['key2']
except KeyError:
pass
或者python有一个类似get()的方法用于嵌套字典?
当前回答
你可以使用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')
其他回答
Glom是一个很好的库,可以进入点查询:
In [1]: from glom import glom
In [2]: data = {'a': {'b': {'c': 'd'}}}
In [3]: glom(data, "a.b.c")
Out[3]: 'd'
查询失败有一个很好的堆栈跟踪,指出确切的故障点:
In [4]: glom(data, "a.b.foo")
---------------------------------------------------------------------------
PathAccessError Traceback (most recent call last)
<ipython-input-4-2a3467493ac4> in <module>
----> 1 glom(data, "a.b.foo")
~/.cache/pypoetry/virtualenvs/neural-knapsack-dE7ihQtM-py3.8/lib/python3.8/site-packages/glom/core.py in glom(target, spec, **kwargs)
2179
2180 if err:
-> 2181 raise err
2182 return ret
2183
PathAccessError: error raised while processing, details below.
Target-spec trace (most recent last):
- Target: {'a': {'b': {'c': 'd'}}}
- Spec: 'a.b.foo'
glom.core.PathAccessError: could not access 'foo', part 2 of Path('a', 'b', 'foo'), got error: KeyError('foo')
默认保护:
In [5]: glom(data, "a.b.foo", default="spam")
Out[5]: 'spam'
格洛姆的魅力在于多功能的规格参数。例如,可以很容易地从以下数据中提取所有的名字:
In [8]: data = {
...: "people": [
...: {"first_name": "Alice", "last_name": "Adams"},
...: {"first_name": "Bob", "last_name": "Barker"}
...: ]
...: }
In [9]: glom(data, ("people", ["first_name"]))
Out[9]: ['Alice', 'Bob']
更多的例子请阅读glom文档。
一个简单的类,可以包装字典,并根据键进行检索:
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 ''
我已经编写了一个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
我稍微改变了一下答案。我添加了检查,如果我们使用列表与数字。 所以现在我们可以用任何一种方法。deep_get(allTemp,[0],{})或deep_get(getMinimalTemp, [0, minimalTemperatureKey], 26)等
def deep_get(_dict, keys, default=None):
def _reducer(d, key):
if isinstance(d, dict):
return d.get(key, default)
if isinstance(d, list):
return d[key] if len(d) > 0 else default
return default
return reduce(_reducer, keys, _dict)
你可以使用pydash:
import pydash as _ #NOTE require `pip install pydash`
_.get(example_dict, 'key1.key2', default='Default')
https://pydash.readthedocs.io/en/latest/api.html