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

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

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


当前回答

减少方法的改进很少,使其与列表一起工作。也使用数据路径作为字符串除以点,而不是数组。

def deep_get(dictionary, path):
    keys = path.split('.')
    return reduce(lambda d, key: d[int(key)] if isinstance(d, list) else d.get(key) if d else None, keys, dictionary)

其他回答

你可以用虚线:

PIP安装

from dotted.collection import DottedDict

assert DottedDict(dict(foo=dict(bar="baz")))["foo"]["bar"] == "baz"
assert DottedDict(dict(foo=dict(bar="baz")))["foo.bar"] == "baz"
assert DottedDict(dict(foo=dict(bar="baz"))).get("lorem.ipsum", None) is None
assert DottedDict(dict(foo=dict(bar="baz"))).get("lorem.ipsum", "default") == "default"

我改编了GenesRus和unutbu的答案,非常简单:

class new_dict(dict):
    def deep_get(self, *args, default=None):
        _empty_dict = {}
        out = self
        for key in args:
            out = out.get(key, _empty_dict)
        return out if out else default

它适用于:

d = new_dict(some_data)
d.deep_get("key1", "key2", "key3", ..., default=some_value)

根据Yoav的回答,一个更安全的方法是:

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

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文档。

在深入获取属性后,我使用点表示法安全地获得嵌套的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)