Python 中的可选链接

Xeo*_*oth 25 python python-3.x

在 JavaScript 中,如果我不确定链中的每个元素是否存在/不是未定义,我可以做foo?.bar,如果bar不存在foo,解释器将悄悄地短路它而不抛出错误。

Python中有没有类似的东西?目前,我一直这样做:

if foo and foo.bar and foo.bar.baz:
    # do something
Run Code Online (Sandbox Code Playgroud)

我的直觉告诉我,这不是检查链中每个元素是否存在的最佳方法。有没有更优雅/Pythonic 的方式来做到这一点?

Ali*_*ich 31

如果它是一本字典,你可以使用get(keyname, value)

{'foo': {'bar': 'baz'}}.get('foo', {}).get('bar')
Run Code Online (Sandbox Code Playgroud)

  • 如果 'foo' 的值为 None 它将下降 (6认同)

Sér*_*ira 15

你可以使用格洛姆。

from glom import glom

target = {'a': {'b': {'c': 'd'}}}
glom(target, 'a.b.c', default=None)  # returns 'd'
Run Code Online (Sandbox Code Playgroud)

https://github.com/mahmoud/glom


sou*_*ole 12

大多数pythonic方式是:

try:
    # do something
    ...
except (NameError, AttributeError) as e:
    # do something else
    ...
Run Code Online (Sandbox Code Playgroud)

  • 我希望有一种方法可以在这里对 python 投反对票:'( (34认同)

the*_*lon 10

您可以使用getattr

getattr(getattr(foo, 'bar', None), 'baz', None)
Run Code Online (Sandbox Code Playgroud)

  • 这并不比OP的“if foo and foo.bar and foo.bar.baz:”更具可读性 (11认同)

Hie*_*nga 6

结合我在这里看到的一些东西。

from functools import reduce


def optional_chain(obj, keys):
    try:
        return reduce(getattr, keys.split('.'), obj)
    except AttributeError:
        return None

optional_chain(foo, 'bar.baz')
Run Code Online (Sandbox Code Playgroud)

或者扩展,getattr这样你也可以使用它作为替代品getattr

from functools import reduce


def optional_chain(obj, keys):
    try:
        return reduce(getattr, keys.split('.'), obj)
    except AttributeError:
        return None

optional_chain(foo, 'bar.baz')
Run Code Online (Sandbox Code Playgroud)

如果路径不存在,它仍然可以引发一个,并且您可以指定自己的默认值而不是“无” rgetattrAttributeError


Ber*_*art 5

将其他一些答案组合到一个函数中可以为我们提供易于阅读的内容以及可以与对象和字典一起使用的内容。

def optional_chain(root, *keys):
    result = root
    for k in keys:
        if isinstance(result, dict):
            result = result.get(k, None)
        else:
            result = getattr(result, k, None)
        if result is None:
            break
    return result
Run Code Online (Sandbox Code Playgroud)

使用此函数,您只需在第一个参数之后添加键/属性。

obj = {'a': {'b': {'c': {'d': 1}}}}
print(optional_chain(obj, 'a', 'b'), optional_chain(obj, 'a', 'z'))
Run Code Online (Sandbox Code Playgroud)

给我们:

{'c': {'d': 1}} None
Run Code Online (Sandbox Code Playgroud)