Title: Augmented assignment doc: clarify 'only evaluated once'
Type: enhancement Stage: needs patch
Components: Documentation Versions: Python 3.11, Python 3.10, Python 3.9
Status: open Resolution:
Dependencies: Superseder:
Assigned To: docs@python Nosy List: docs@python, ezio.melotti, loewis, terry.reedy
Priority: normal Keywords:

Created on 2014-04-26 20:38 by terry.reedy, last changed 2021-10-21 23:26 by iritkatriel.

Messages (2)
msg217212 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2014-04-26 20:38
"An augmented assignment expression like x += 1 can be rewritten as x = x + 1 to achieve a similar, but not exactly equal effect. In the augmented version, x is only evaluated once."

As discussed and demonstrated as part of #21101 (see msg 215560) and following, this is not exactly true in current CPython. If the expression 'x' is 'y[k]', then the subscription is performed twice, once to get and once to set. Both y and k are still evaluated just once.

def ob():
   print('ob fetched')
   return d

def key():
   print('key called')
   return 0

d = [[]]
ob()[key()] += [1]

# prints
ob fetched
key called

I suggest changing "x is only evaluated once." to something like

"x is usually only evaluated once. However, if x has the form y[k], y and k are evaluated once but the subscription may be done twice, once to get and once to set."

I intentionally said 'subscription may be' rather than 'subscription is' because implementations should remain free to do the subscription (and the whole expression x) just once -- by directly replacing the reference to the old value in the internals of the mapping structure with a reference to the new value.

#16701 discusses possible ambiguity in the next sentence, about 'in place'.
msg217217 - (view) Author: Martin v. Löwis (loewis) * (Python committer) Date: 2014-04-26 21:03
This is not limited to dictionaries. Augmented assignment *always* involves a read operation and a write operation. 
So Antoine's remark in msg215573 is more general;

a.x += 1

has a get and a set, and even

x += 1

has a get and a set.

I still agree that the original statement is confusing. It (implicitly) claims that 

  x = x + 1

evaluates x twice, which it does not. Instead, x is only *evaluated* once, and then written to. Only if x has subexpressions, they get evaluated only once ("evaluation" being the thing that produces a "value").
Date User Action Args
2021-10-21 23:26:19iritkatrielsetversions: + Python 3.9, Python 3.10, Python 3.11, - Python 2.7, Python 3.4, Python 3.5
2014-06-29 10:23:07ezio.melottisetnosy: + ezio.melotti
2014-04-26 21:03:57loewissetnosy: + loewis
messages: + msg217217
2014-04-26 20:38:59terry.reedycreate