[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