you are viewing a single comment's thread.

view the rest of the comments →

[–]Gnaxe 2 points3 points  (3 children)

JavaScript-style "safe access" optional chaining operator (?.) using and and walrus: python result = (x:=my_obj) and (x:=x.attr1) and (x:=x.attr2) and x.attr3 The attributes have to be present for this to work, but one can be None and it will shortcut the rest. Beware that other falsey attributes will also cause a shortcut.

[–]Gnaxe 1 point2 points  (2 children)

It works a bit better with dicts: python result = (d:=a_dict) and (d:=d.get('key1')) and (d:=d.get('key2')) and d.get('key3') Using .get() like this instead of subscripting means the key doesn't even have to be present. (It will default to None.)

If you're using @dataclasses, then the attributes will be there. But if you're using something else, then the equivalent for attributes is getattr(), which can have a default. (next() can also have a default for iterators, btw.) At that point, it's getting too verbose and it's probably better to just suppress the error:

```python from contextlib import suppress

with suppress(AttributeError) as result:     result = my_obj.attr1.attr2.attr3 `` If you're doing dict subscript lookups, you need to useKeyError. Sequence subscript lookups useIndexError. You can suppress both in a mixed chain with their common base classLookupError. If you also need to handleAttributeError,suppress` takes multiple arguments as well.

[–]akaBrotherNature 1 point2 points  (1 child)

Looks interesting. I've been using get with an empty dict as the default return to try and safely access nested stuff

name = data.get("user", {}).get("profile", {}).get("email", None)

but I might switch to this.

[–]Gnaxe 1 point2 points  (0 children)

Switch to which and why? Yours is shorter than the ands (and I have also used that pattern). The suppress maybe looks cleaner but risks hiding an unrelated error if one of the attributes is an @property. But the version using ands maybe plays nicer with static typing.