我有一本嵌套的字典。是否只有一种方法可以安全地传递价值观?

try:
    example_dict['key1']['key2']
except KeyError:
    pass

或者python有一个类似get()的方法用于嵌套字典?


当前回答

还有一个相同功能的函数,也返回一个布尔值来表示是否找到键,并处理一些意想不到的错误。

'''
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', ''))

(真的,大声叫) (假的,”)

其他回答

你可以使用开源ndicts包中的NestedDict(我是作者),它有一个完全像字典一样的安全get方法。

>>> from ndicts import NestedDict
>>> nd = NestedDict({"key1": {"key2": 0}}
>>> nd.get(("key1", "key2))
0
>>> nd.get("asd")

你可以使用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')

在第一阶段,你可以得到一个空字典。

example_dict.get('key1',{}).get('key2')

你也可以使用python reduce:

def deep_get(dictionary, *keys):
    return reduce(lambda d, key: d.get(key) if d else None, keys, dictionary)

下面是一个基于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