我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?
try:
example_dict['key1']['key2']
except KeyError:
pass
或者python有一个类似get()的方法用于嵌套字典?
我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?
try:
example_dict['key1']['key2']
except KeyError:
pass
或者python有一个类似get()的方法用于嵌套字典?
当前回答
在深入获取属性后,我使用点表示法安全地获得嵌套的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)
其他回答
下面是一个基于unutbu函数答案的解决方案:
Python命名指南 默认值作为参数 不用try,只是检查key是否在object上
def safe_get(dictionary, *keys, default=None):
for key in keys:
if key not in dictionary:
return default
dictionary = dictionary[key]
return dictionary
在深入获取属性后,我使用点表示法安全地获得嵌套的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)
在第一阶段,你可以得到一个空字典。
example_dict.get('key1',{}).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')
通过把所有这些答案和我做的小改变结合起来,我认为这个函数会很有用。安全、快捷、易于维护。
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