Optional Chaining in Python

Migel Hewage Nimesha Oct 10, 2023
  1. Use try-except to Implement Optional Chaining in Python
  2. Use getattr to Implement Optional Chaining in Python
  3. Use get(key, value) to Implement Optional Chaining in Python
  4. Use a Combination of Methods to Implement Optional Chaining in Python
  5. Use getattr as a Drop-In to Implement Optional Chaining in Python
  6. Use glom to Implement Optional Chaining in Python
  7. Use a Readable Method With Dictionaries and Objects to Implement Optional Chaining in Python
  8. Conclusion
Optional Chaining in Python

Python is a programming language used mainly in system scripting, server-side web development, and software development. Also, it consists of simple syntaxes that improve the readability of the code.

Among the features in Python, optional chaining is a safe and concise way of accessing nested object properties. It is the process of calling and querying the properties that may be null or may not be null at the time.

By using optional chaining, we can check internally whether a property in an object is available rather than checking manually.

The optional chaining checks if the property left to the operator is defined or undefined. If the property is not null, the call succeeds and returns undefined if it is invalid or undefined.

Here, it returns an undefined value instead of reporting an error. Also, this works fine with the function calls even though the method may not exist.

This concept was introduced recently by ECMA International, Technical Committee 39 – ECMAScript, authored by Claude Pache, Gabriel Isenberg, Daniel Rosenwasser, and Dustin Savery.

When writing cleaner code, optional chaining is a nice feature to use.

Below are some methods we can use in implementing optional chaining in Python. We can use these code chunks when building the functions.

Use try-except to Implement Optional Chaining in Python

The most pythonic way of optional chaining is below.

try:
    # statements

except (NameError, AttributeError) as e:
    # statements (else)

This method uses the try command and the except command. Within try it contains the statements used in controlling the flow, while except consists of statements used in handling the errors occurring in passing the instructions to the program.

When a program executes, exceptions can occur. Then they interrupt the program by printing out a message displaying the error and how it happened.

To prevent interruption, we have to catch them. So, handling exceptions like this will aid in getting error-proof code.

Here we are considering two main errors: NameError and AttributeError. When we use an undefined variable or a function, NameError can occur.

If the user tries making an invalid attribute reference, the reference will fail, and AttributeError can occur. Also, spelling variations will raise as AttributeError.

As discussed above, this pythonic approach of optional chaining aids in calling the properties, even if they are defined or not, while handling the exceptions.

Use getattr to Implement Optional Chaining in Python

Instead of the above method, using getattr is also another method in optional chaining.

getattr(getattr(foo, "bar", None), "baz", None)

Here we use the getattr function that returns the value of the named attribute from the specified object. The object name should be a string, and if it is a named attribute, it returns the value of that attribute.

But, if the named attribute does not exist, the default value is returned or throws an AttributeError.

Within this getattr function, getattr(foo, 'bar', None) is the object while baz is the attribute and None is the default value.

Use get(key, value) to Implement Optional Chaining in Python

We can use get(key, value) when it is a dictionary.

{"foo": {"bar": "baz"}}.get("foo", {}).get("bar")

Dictionary is a collection of ordered, changeable, and non-duplicate data values stored as key: value pairs. Here, 'foo', 'bar', and 'baz' are the placeholders we use in Python.

{'foo': {'bar': 'baz'}} is the dictionary, and with it, we are using two get functions with a key and a value. Here the get function returns the item’s value with the specified key.

The first get function consists of a key as 'foo' and a value of {} while the second consists only of a key as 'bar'.

As in the above code snippet, we can adapt the optional chaining concept even when we use a dictionary.

Use a Combination of Methods to Implement Optional Chaining in Python

Below is another method we can follow in optional chaining. It is a combination of methods.

from functools import reduce


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


optional_chain(foo, "bar.baz")

At first, we have to import the reduce module from the functools that store the intermediate result and return only the final summation. Then the function optional_chain is defined with two parameters.

After that, we can adapt the first discussed method with try and the except controls. Within the try and except commands, we have used the getattr function.

We have described the functionality of getattr in the second method. Finally, we call the optional_chain by defining two parameters.

Use getattr as a Drop-In to Implement Optional Chaining in Python

We can use it as a drop-in without extending the getattr as above.

from functools import reduce


def rgetattr(obj, attr, *args):
    def _getattr(obj, attr):
        return getattr(obj, attr, *args)

    return reduce(_getattr, attr.split("."), obj)

After importing the module, we defined a function named rgetattr with three parameters. Then we define the function getattr as a drop-in.

If the path does not exist, rgetattr will throw an AttributeError, and we can specify default instead of None.

Use glom to Implement Optional Chaining in Python

Another method we can use in optional chaining is using glom.

from glom import glom

target = {"a": {"b": {"c": "d"}}}
glom(target, "a.b.c", default=None)

As the first step, we should import the module glom from the library. Then the target has been defined in the form of a dictionary with a, b, and c. Also, d is the corresponding value of c.

After that, the function glom has called with target and a.b.c inside it. If any exception occurs, it will print None as the default value.

Use a Readable Method With Dictionaries and Objects to Implement Optional Chaining in Python

By adapting to the below method, we can make the code more readable when used with dictionaries and objects.

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

At first, it defined a function named optional_chain and proceeded with a for loop and if-else statements. It used the getattr function within the flow to obtain the result in the else part.

We must add keys after the first argument when using this function.

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

Conclusion

Overall, the above methods are the ways we can adapt when we need optional chaining in Python.

We can use the try and except approaches and avoid premature optimizations if we know the process and performance problem we solve. Also, we can have a reflection of code by using getattr.

Migel Hewage Nimesha avatar Migel Hewage Nimesha avatar

Nimesha is a Full-stack Software Engineer for more than five years, he loves technology, as technology has the power to solve our many problems within just a minute. He have been contributing to various projects over the last 5+ years and working with almost all the so-called 03 tiers(DB, M-Tier, and Client). Recently, he has started working with DevOps technologies such as Azure administration, Kubernetes, Terraform automation, and Bash scripting as well.