
On 2016-10-31 17:16, Guido van Rossum wrote:
I think we should try to improve our intutition about these operators. Many things that are intuitively clear still require long turgid paragraphs in reference documentation to state the behavior unambiguously -- but that doesn't stop us from intuitively grasping concepts like a+b (when does b.__radd__ get called?) or @classmethod.
The main case to build intuition for is "?." -- once you get that the "?[...]" operator works just the same. So here's my attempt:
*In a series of attribute accesses like "foo.bar.baz.bletch", putting a `?` before a specific dot inserts a None check for the expression to the left and skips everything to the right when the None check is true.*
We still need to clarify what we mean by "expression to the left" and "everything to the right", but in most situations you will guess right without thinking about it.
The expression to the left is easy -- it's determined by syntactic operator precedence, so that if we have "x = y + foo.bar?.baz.bletch", the expression to the left of the "?." is just "foo.bar". (But see below -- you won't actually see such usage much.)
For "everything to the right" it would seem we have some freedom: e.g. if we have "foo.bar?.baz(bletch)" is the call included? The answer is yes -- the concept we're after here is named "trailer" in the Grammar file in the source code (https://github.com/python/cpython/blob/master/Grammar/Grammar#L119), and "primary" in the reference manual (https://docs.python.org/3/reference/expressions.html#primaries). This means all attribute references ("x.y"), index/slice operations ("x[...]"), and calls ("x(...)").
Note that in almost all cases the "?." operator will be used in an context where there is no other operator of lower precedence before or after it -- given the above meaning, it doesn't make a lot of sense to write "1 + x?.a" because "1 + None" is always an error (and ditto for "x?.a + 1"). However it still makes sense to assign such an expression to a variable or pass it as an argument to a function.
So you can ignore the preceding four paragraphs: just remember the simplified rule (indented and in bold, depending on your email client) and let your intuition do the rest. Maybe it can even be simplified more:
*The "?." operator splits the expression in two parts; the second part is skipped if the first part is None. *
Eventually this *will* become intuitive. The various constraints are all naturally imposed by the grammar so you won't have to think about them consciously.
Would it help if we referred to them collectively as "suffixes"? Coincidentally, David Mertz's post includes a case where this feature would shorten the code. In normal Python form his code has: if x in stop_on or (end_if and end_if(x)): With this feature it could be: if x in stop_on or end_if?(x):