On Mon, Oct 31, 2016 at 05:44:07PM -0400, Random832 wrote:
Right now, foo.bar.baz(bletch) is Call(Attribute(Attribute(Name('foo'), 'bar'), 'baz'), [Name('bletch')])), which is identical to (foo.bar).baz(bletch) or (foo.bar.baz)(bletch). These are treated, essentially, as postfix operators, where you can parenthesize any left part of the expression and leave its meaning [and its AST] unchanged.
Is the AST going to be unchanged, leading to the conclusion that the short-circuiting in (foo?.bar).baz will "reach outside of" the parentheses, and relying on the fact that wanting to do that with None is a silly thing to do in almost all cases?
I hope not. Even if it is "a silly thing to do in almost all cases", nevertheless it makes it hard to think about code if the ?. operator can reach outside of parentheses. If it can do that, just how far outside will it reach?
Besides, "almost all" is not "all". For example:
I expect that the first case would be equivalent to:
None if spam is None else spam.attr.__class__.__name__
and the second case would be equivalent to:
(None if spam is None else spam.attr).__class__.__name__
Concrete example: given spam = None, the first unparenthised version will return None, while the second parenthised version will return 'NoneType'.
I don't know when I would ever want to actually do this in practice, but allowing the ?. operator to magically effect code outside of the parentheses definitely counts as "spooky action at a distance". Guido's rule of "everything to the right" is easy to reason about if "to the right" ends where the parenthised expression ends.
 Actually I don't, or at least I didn't. I expected ?. to apply only to a single look-up. But Guido's description of the "everything to the right" rule seems like it will probably be more useful in practice and allow us to avoid writing long chains of spam?.eggs?.cheese?.tomato. So I'm changing my expectations.