Return value of an assignment statement?

Terry Reedy tjreedy at udel.edu
Sat Feb 23 19:34:35 EST 2008


"Tim Roberts" <timr at probo.com> wrote in message 
news:vb81s3d571fplh5dbv5uinhiu74gg1k7hl at 4ax.com...
| Marc 'BlackJack' Rintsch <bj_666 at gmx.net> wrote:
|
| >On Fri, 22 Feb 2008 11:00:17 -0800, Aahz wrote:
| >
| >> It's just too convenient to be able to write
| >>
| >> L += ['foo']
| >>
| >> without rebinding L.
| >
| ><nitpick>But ``+=`` does rebind.</nitpick>
|
| Usually, but there's an exception for lists, which a specific
| implementation for += that calls "append".  Or do I misunderstand you?

There is no exception at the compiler level, and indeed, cannot be, because 
in general, the compiler *does not know* the types of either target or 
augment.

target += augment

is compiled, in effect, as

compute target and load target_object
compute and load augment_object
call target_object.__iadd__(augment_object)
store return_object at target

 In the list case, the rebinding is to the *same* object! --
because list.__iadd(l1,l2)__  returns l1 extended with l2 rather than a new 
list l1+l2, as the specification allows.

Augmented (inplace) assignment is still assignment (binding).

| C:\tmp>python
| Python 2.4.4 (#71, Oct 18 2006, 08:34:43) [MSC v.1310 32 bit (Intel)] on
| win32
| Type "help", "copyright", "credits" or "license" for more information.
| >>> L = [1,2,3]
| >>> id(L)
| 10351000
| >>> L += [4]
| >>> id(L)
| 10351000

L has been rebound to the same object, hence same id.  Unfortunately, such 
rebinding is only visible (that I can think of) when it fails:

>>> t=([],)
>>> t[0]+=[1]

Traceback (most recent call last):
  File "<pyshell#8>", line 1, in -toplevel-
    t[0]+=[1]
TypeError: object does not support item assignment
>>> t
([1],)

The list comprising t[0] is extended by its __iadd__ method.  The exception 
arises due to the subsequent attempted rebinding to t[0] (see dis output 
below), which is, of course, not permissible.

>>> t[0].extend([2])
>>> t
([1, 2],)

Extension without attempted illegal rebinding raises no error.

CPython specifics:

>>> from dis import dis

>>> def fi(i): i+=1; return i
>>> dis(fi)
  1           0 LOAD_FAST                0 (i)
              3 LOAD_CONST               1 (1)
              6 INPLACE_ADD
              7 STORE_FAST               0 (i)
             10 LOAD_FAST                0 (i)
             13 RETURN_VALUE

>>> def fl(l): l += [1]; return l
>>> dis(fl)
  1           0 LOAD_FAST                0 (l)
              3 LOAD_CONST               1 (1)
              6 BUILD_LIST               1
              9 INPLACE_ADD
             10 STORE_FAST               0 (l)
             13 LOAD_FAST                0 (l)
             16 RETURN_VALUE

Treating the VM stack as a Python list, INPLACE_ADD executes
something like

stack[-2] = stack[-2].__iadd__(stack[-1])
stack.pop() # leaving returned object on top of stack

Terry Jan Reedy









More information about the Python-list mailing list