我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?
try:
example_dict['key1']['key2']
except KeyError:
pass
或者python有一个类似get()的方法用于嵌套字典?
我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?
try:
example_dict['key1']['key2']
except KeyError:
pass
或者python有一个类似get()的方法用于嵌套字典?
当前回答
通过把所有这些答案和我做的小改变结合起来,我认为这个函数会很有用。安全、快捷、易于维护。
def deep_get(dictionary, keys, default=None):
return reduce(lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary)
例子:
from functools import reduce
def deep_get(dictionary, keys, default=None):
return reduce(lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary)
person = {'person':{'name':{'first':'John'}}}
print(deep_get(person, "person.name.first")) # John
print(deep_get(person, "person.name.lastname")) # None
print(deep_get(person, "person.name.lastname", default="No lastname")) # No lastname
其他回答
我使用的一个解决方案类似于double get,但具有使用if else逻辑避免TypeError的额外能力:
value = example_dict['key1']['key2'] if example_dict.get('key1') and example_dict['key1'].get('key2') else default_value
然而,字典嵌套越多,这就变得越麻烦。
因为如果缺少一个键就会引发一个键错误是合理的,我们甚至可以不检查它,让它像这样单一:
def get_dict(d, kl):
cur = d[kl[0]]
return get_dict(cur, kl[1:]) if len(kl) > 1 else cur
在深入获取属性后,我使用点表示法安全地获得嵌套的dict值。这适用于我,因为我的字典是反序列化的MongoDB对象,所以我知道键名不包含.s。此外,在我的上下文中,我可以指定一个数据中没有的虚假回退值(None),因此在调用函数时可以避免使用try/except模式。
from functools import reduce # Python 3
def deepgetitem(obj, item, fallback=None):
"""Steps through an item chain to get the ultimate value.
If ultimate value or path to value does not exist, does not raise
an exception and instead returns `fallback`.
>>> d = {'snl_final': {'about': {'_icsd': {'icsd_id': 1}}}}
>>> deepgetitem(d, 'snl_final.about._icsd.icsd_id')
1
>>> deepgetitem(d, 'snl_final.about._sandbox.sbx_id')
>>>
"""
def getitem(obj, name):
try:
return obj[name]
except (KeyError, TypeError):
return fallback
return reduce(getitem, item.split('.'), obj)
def safeget(_dct, *_keys):
if not isinstance(_dct, dict): raise TypeError("Is not instance of dict")
def foo(dct, *keys):
if len(keys) == 0: return dct
elif not isinstance(_dct, dict): return None
else: return foo(dct.get(keys[0], None), *keys[1:])
return foo(_dct, *_keys)
assert safeget(dict()) == dict()
assert safeget(dict(), "test") == None
assert safeget(dict([["a", 1],["b", 2]]),"a", "d") == None
assert safeget(dict([["a", 1],["b", 2]]),"a") == 1
assert safeget({"a":{"b":{"c": 2}},"d":1}, "a", "b")["c"] == 2
通过把所有这些答案和我做的小改变结合起来,我认为这个函数会很有用。安全、快捷、易于维护。
def deep_get(dictionary, keys, default=None):
return reduce(lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary)
例子:
from functools import reduce
def deep_get(dictionary, keys, default=None):
return reduce(lambda d, key: d.get(key, default) if isinstance(d, dict) else default, keys.split("."), dictionary)
person = {'person':{'name':{'first':'John'}}}
print(deep_get(person, "person.name.first")) # John
print(deep_get(person, "person.name.lastname")) # None
print(deep_get(person, "person.name.lastname", default="No lastname")) # No lastname