Not exactly. Protecting from a missing attribute/key already exists and is spelled getattr(obj, "attribute", None) or dictionary.get(key, None).
Broadly, in Ruby/JS/etc. such operators protect against the object/collection itself being None, e.g. same as the expression obj.attribute if obj is not None else None, or shorter but looser obj and obj.attribute (hence Ruby’s spelling obj&.attribute).
Moreover, x?.y should still fail if x is not None but lacks .y attribute!
Such expressions get much clumsier to build once you chain things e.g. writing x?.y?.z would become something like
None if x is None else None if x.y is None else x.y.z
or equivalently
x.y.z if x is not None and x.y is not None else None
or approximately
x and x.y and x.y.z
except it should only evaluate x.y once. That last quality is hard to achieve in an expression!
However it’s pretty easy to achieve with new helper functions e.g.
def andgetattr(maybe_obj, attr):
if maybe_obj is None:
return None
return getattr(maybe_obj, attr)
andgetattr(andgetattr(x, 'y'), 'z')
Not pretty, especially after you define andgetitem, andcall helpers for collections & methods… Compare foo?.bar?[baz]?.quux?(arg1, arg2) with andcall(andgetattr(andgetitem(andgetattr(foo, 'bar'), baz), 'quux'), arg1, arg2).
Hmm that really begs for left-to-right version, something like dig(foo, 'bar', [baz], 'quux', (arg1, arg2,)) — using strings to denote x.attr, lists for x[indexing], tuples for x(calling)? ![]()
I’m not convinced such operator would be great fit for Python. But that’s^ the clumsiness it tries to improve upon.
It tends to exist in languages where common APIs/operations return such values a lot. JS obj.no_such_attr aka obj['no_such_attr'] fails by returning undefined; Ruby hash[no_such_key] fails by returning nil…
Whereas Python raises exceptions — unless you specify explicit defaults to getattr() / dict.get().
For dictionaries, this pattern works great: (d or {}).get('e', {}).get('f', {})
I’d look for things that extend those…