[Python-ideas] PEP 505: None-aware operators
Steve Dower
steve.dower at python.org
Wed Jul 18 17:29:37 EDT 2018
Thanks! Bit of discussion below about precedence, but thanks for
spotting the typos.
On 18Jul2018 1318, MRAB wrote:
> On 2018-07-18 18:43, Steve Dower wrote:
>> Grammar changes
>> ---------------
>>
>> The following rules of the Python grammar are updated to read::
>>
>> augassign: ('+=' | '-=' | '*=' | '@=' | '/=' | '%=' | '&=' | '|=' |
>> '^=' |
>> '<<=' | '>>=' | '**=' | '//=' | '??=')
>>
>> power: coalesce ['**' factor]
>> coalesce: atom_expr ['??' factor]
>> atom_expr: ['await'] atom trailer*
>> trailer: ('(' [arglist] ')' |
>> '[' subscriptlist ']' |
>> '?[' subscriptlist ']' |
>> '.' NAME |
>> '?.' NAME)
>>
> The precedence is higher than I expected. I think of it more like 'or'.
> What is its precedence in the other languages?
Yes, I expected this to be the contentious part. I may have to add a bit
of discussion.
Mostly, I applied intuition rather than copying other languages on
precedence (and if you could go through my non-git history, you'd see I
tried four other places ;) ). The most "obvious" cases were these::
a ?? 1 + b()
b ** a() ?? 2
In the first case, both "(a ?? 1) + b()" and "a ?? (1 + b())" make
sense, so it's really just my own personal preference that I think it
looks like the first. If you flip the operands to get "b() + a ?? 1"
then you end up with either "b() + (a ?? 1)" or "(b() + a) ?? 1", then
it's more obvious that the latter doesn't make any sense (why would
__add__ return None?), and so binding more tightly than "+" helps write
sensible expressions with fewer parentheses.
Similarly, I feel like "b ** (a() ?? 2)" makes more sense than "(b **
a()) ?? 2", where for the latter we would have to assume a __pow__
implementation that returns None, or one that handles being passed None
without raising a TypeError.
Contrasting this with "or", it is totally legitimate for arithmetic
operators to return falsey values.
As I open the text file to correct the typos, I see this is what I tried
to capture with:
> Inserting the ``coalesce`` rule in this location ensures that expressions
> resulting in ``None`` are naturally coalesced before they are used in
> operations that would typically raise ``TypeError``.
Take (2 ** a.b) ?? 0. The result of __pow__ is rarely going to be None,
unless we train all the builtin types to do so (which, incidentally, I
am not proposing and have no intention of proposing), whereas something
like "2 ** coord?.exponent" attempting to call "2.__pow__(None)" seems
comparatively likely. (Unfortunately, nobody writes code like this yet
:) So there aren't any real-life examples. Originally I didn't include
"??" in the proposal, but it became obvious in the examples that the
presence of None-propagating operators ?. and ?[] just cause more pain
without having the None-terminating operator ?? as well.)
>> Inserting the ``coalesce`` rule in this location ensures that expressions
>> resulting in ``None`` are natuarlly coalesced before they are used in
>
> Typo "natuarlly".
Thanks.
>> assert a == 'value'
>> assert b == ''
>> assert c == '0' and any(os.scandir('/'))
>
> Wouldn't the last assertion fail, because c == 0?
Correct, another typo.
Cheers,
Steve
More information about the Python-ideas
mailing list