Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

315
Views
Optional chaining in Python

In JavaScript, if I'm not sure whether every element of the chain exists/is not undefined, I can do foo?.bar, and if bar does not exist on foo, the interpreter will silently short circuit it and not throw an error.

Is there anything similar in Python? For now, I've been doing it like this:

if foo and foo.bar and foo.bar.baz:
    # do something

My intuition tells me that this isn't the best way to check whether every element of the chain exists. Is there a more elegant/Pythonic way to do this?

over 4 years ago · Hanz Gallego
7 answers
Answer question

0

You can use getattr:

getattr(getattr(foo, 'bar', None), 'baz', None)
over 4 years ago · Hanz Gallego Report

0

Most pythonic way is:

try:
    # do something
    ...
except (NameError, AttributeError) as e:
    # do something else
    ...
over 4 years ago · Hanz Gallego Report

0

If it's a dictionary you can use get(keyname, value)

{'foo': {'bar': 'baz'}}.get('foo', {}).get('bar')
over 4 years ago · Hanz Gallego Report

0

Combining some of the other answers into a function gives us something that's easily readable and something that can be used with objects and dictionaries.

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

Using this function you'd just add the keys/attributes after the first argument.

obj = {'a': {'b': {'c': {'d': 1}}}}
print(optional_chain(obj, 'a', 'b'), optional_chain(obj, 'a', 'z'))

Gives us:

{'c': {'d': 1}} None
over 4 years ago · Hanz Gallego Report

0

You can use the Glom.

from glom import glom

target = {'a': {'b': {'c': 'd'}}}
glom(target, 'a.b.c', default=None)  # returns 'd'
over 4 years ago · Hanz Gallego Report

0

Combining a few things I see here.

from functools import reduce


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

optional_chain(foo, 'bar.baz')

Or instead extend getattr so you can also use it as a drop-in replacement for getattr

from functools import reduce


def rgetattr(obj, attr, *args):
    def _getattr(obj, attr):
        return getattr(obj, attr, *args)
    return reduce(_getattr, attr.split('.'), obj)

With rgetattr it can still raise an AttributeError if the path does not exist, and you can specify your own default instead of None.

over 4 years ago · Hanz Gallego Report

0

I like modern languages like Kotlin which allow this:

foo?.bar?.baz

Recently I had fun trying to implement something similar in python: https://gist.github.com/karbachinsky/cc5164b77b09170edce7e67e57f1636c

Unfortunately, the question mark is not a valid symbol in attribute names in python, thus I used a similar mark from Unicode :)

over 4 years ago · Hanz Gallego Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!