[Python-ideas] Why does += trigger UnboundLocalError?

Terry Reedy tjreedy at udel.edu
Thu Jun 2 00:42:03 CEST 2011


On 6/1/2011 1:32 PM, Bruce Leban wrote:

>  >>> def f(x,y):
> x += y
>  >>> dis.dis(f)
>    2           0 LOAD_FAST                0 (x)
>                3 LOAD_FAST                1 (y)
>                6 *INPLACE_ADD*
>                7 STORE_FAST               0 (x)
>               10 LOAD_CONST               0 (None)
>               13 RETURN_VALUE
>  >>> def g(x,y):
> x = x + y
>
>  >>> dis.dis(g)
>    2           0 LOAD_FAST                0 (x)
>                3 LOAD_FAST                1 (y)
>                6 *BINARY_ADD*
>                7 STORE_FAST               0 (x)
>               10 LOAD_CONST               0 (None)
>               13 RETURN_VALUE

(In 3.2, one no longer needs to wrap code in a function to dis it.
see below.)

To see the 'calculate the source/target just once instead of twice' 
part, you need a source/target that actually requires calculation.

 >>> from dis import dis
 >>> dis('x[i] = x[i] + 1')
   1           0 LOAD_NAME                0 (x)
               3 LOAD_NAME                1 (i)
               6 BINARY_SUBSCR
               7 LOAD_CONST               0 (1)
              10 BINARY_ADD
              11 LOAD_NAME                0 (x)
              14 LOAD_NAME                1 (i)
              17 STORE_SUBSCR
              18 LOAD_CONST               1 (None)
              21 RETURN_VALUE

 >>> dis('x[i] += 1')
   1           0 LOAD_NAME                0 (x)
               3 LOAD_NAME                1 (i)
               6 DUP_TOP_TWO
               7 BINARY_SUBSCR
               8 LOAD_CONST               0 (1)
              11 INPLACE_ADD
              12 ROT_THREE
              13 STORE_SUBSCR
              14 LOAD_CONST               1 (None)
              17 RETURN_VALUE

Even this does not show much difference as the dup and rotate substitute 
for two loads but do not actually save any calculation. However,

 >>> dis('a.b[c+d] = a.b[c+d] + 1')
   1           0 LOAD_NAME                0 (a)
               3 LOAD_ATTR                1 (b)
               6 LOAD_NAME                2 (c)
               9 LOAD_NAME                3 (d)
              12 BINARY_ADD
              13 BINARY_SUBSCR
              14 LOAD_CONST               0 (1)
              17 BINARY_ADD
              18 LOAD_NAME                0 (a)
              21 LOAD_ATTR                1 (b)
              24 LOAD_NAME                2 (c)
              27 LOAD_NAME                3 (d)
              30 BINARY_ADD
              31 STORE_SUBSCR
              32 LOAD_CONST               1 (None)
              35 RETURN_VALUE

 >>> dis('a.b[c+d] += 1')
   1           0 LOAD_NAME                0 (a)
               3 LOAD_ATTR                1 (b)
               6 LOAD_NAME                2 (c)
               9 LOAD_NAME                3 (d)
              12 BINARY_ADD
              13 DUP_TOP_TWO
              14 BINARY_SUBSCR
              15 LOAD_CONST               0 (1)
              18 INPLACE_ADD
              19 ROT_THREE
              20 STORE_SUBSCR
              21 LOAD_CONST               1 (None)
              24 RETURN_VALUE

The latter has the same dup-rotate in place of a bit more calculation. 
The same would be true of, for instance, f(a).b.

-- 
Terry Jan Reedy




More information about the Python-ideas mailing list