[Python-Dev] PEP 572 semantics: all capabilities of the assignment statement

Guido van Rossum guido at python.org
Thu Jul 5 19:46:45 EDT 2018


On Thu, Jul 5, 2018 at 3:45 PM Nick Coghlan <ncoghlan at gmail.com> wrote:

>
>
> On Thu., 5 Jul. 2018, 3:17 pm Guido van Rossum, <guido at python.org> wrote:
>
>> Let me be slightly contrarian. :-)
>>
>> On Wed, Jul 4, 2018 at 9:12 PM Chris Angelico <rosuav at gmail.com> wrote:
>>
>>> Definitely against augmentation, for several reasons:
>>>
>>> 1) Spelling - should it be :+= or +:= ?
>>>
>>
>> That one's easy. As Nick's (withdrawn) PEP 577 shows it should be simply
>> `+=`.
>>
>>
>>> 2) Is the result of the expression the modified value or the original?
>>>
>>
>> Someone (sadly I forget who) showed, convincingly (to me anyways :-) that
>> it should return whatever the `__iadd__` method returns, or (if there isn't
>> one) the result of `a = a + b`.
>>
>
> I think I had it as an open question in one of the earlier drafts of PEP
> 577.
>
> The subsequent rationale for it returning the modified value was that we
> have this existing equivalence at the statement level:
>
>     a += b
>     a = operator.iadd(a, b)
>
> So the natural expression level semantics would be:
>
>     a := operator.iadd(a, b)
>

Thinking about it more, I think the real stumper was what should happen for
either of these:

x = (a.b := 1)
x = (a.b += 1)

Take the first one and let's try to compile it to pseudo bytecode (which
I'm making up on the spot but should be simple enough to understand if
you've seen output from the "dis" module):

LOAD 1
LOAD a
SETATTR b
???

What do we do next? We could do

LOAD a
GETATTR b
STORE x

But this gives a's class the opportunity to change the value (because its
__setattr__ could normalize the value, e.g. to a string or a float, and
then its __getattribute__ would return the normalized value). But this
seems a rare case and wastes time in the common case, and also seems
somewhat more surprising than always assinging 1 to x regardless of what
SETATTR did, so I'd rather forgo the extra GETATTR operation. So I think it
should be

LOAD 1
DUP
LOAD a
SETATTR b
LOAD r1
STORE x

I think the second example could be translated as follows (using a register
rather than a sequence of DUPs and ROTs to save the extra copy of the
result of the IADD that we want to store into x).

LOAD a
DUP
GETATTR b
LOAD 1
IADD
COPY .r1  # copy into register r1
SETATTR b  # this uses the reference to a that was left on the stack by DUP
LOAD .r1
STORE x

I used pen and paper to figure out what was on the stack at each point and
had to rewrite the pseudo bytecode several times. But now I'm pretty sure
this will pose no serious challenge for bytecode generation.

But I'd like to point out to anyone who made it this far that this is not
part of PEP 572! The PEP currently proposes neither "+=" in expressions nor
targets that are attributes -- it only proposes "NAME := EXPR" because for
the others the use cases are just too thin. (But in the past we said that
about things like "(1, 2, *args, *more_args)" and eventually we found
enough use cases for them that they were added. :-)

-- 
--Guido van Rossum (python.org/~guido)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20180705/372afd62/attachment-0001.html>


More information about the Python-Dev mailing list