I’ve realized that there is a key part of how I’ve been mentally “framing” and parsing each of these that is actually not stated in the PEP at all (and at a quick skim, the PEP seems to be rejecting outright).
When I’ve been reading obj?.attr
, I think of it as obj? .attr
not obj ?.attr
i.e. the question that I’m asking in the expression is “Is obj None?”, not “Does obj have attr?”
“Is obj None?” is equivalent to None if obj is None else obj.attr
whereas “Does obj have attr?” is equivalent to getattr(obj, "attr", None)
I have a rudimentary (at best) understanding of parsing grammars, but I think what I actually want is it to be a “unary postfix operator”, but the actual implementation is adding ?.
and ?[...]
“trailers” for weird grammar reasons that I don’t understand and just assumed must have been the easier way for internal implementation details.
There’s the unary postfix operator section under Rejected Ideas, but it’s mostly about returning a NoneQuestion
type that implements dunder methods to return itself, rather than short-circuiting in the expression evaluation grammar.
It’s also addresses the problem of some other combining rules with expressions like:
What should x? + 1
mean?
My answer to that is that I would have it mean:
(None if x is None else x) + 1
Python lets me do that currently, but it’s pretty obvious that it’s risking a TypeError
In [1]: x = 1
In [2]: (None if x is None else x) + 1
Out[2]: 2
In [3]: x = None
In [4]: (None if x is None else x) + 1
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
Cell In[4], line 1
----> 1 (None if x is None else x) + 1
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
edit: I actually had put a few different times in earlier draft comments (but then removed before posting since it didn’t feel relevant) that I might like to write
engineer = machine.line?.department.engineer?
as a visual indicator that I know line
and engineer
could be None
, and I don’t care that the final ?
there is a no-op and could be removed without affecting anything