+=
operator is considered as an assignment when used with simple variables. So, Python while parsing the function body will add variable
in <function_object>.func_code.co_varnames
, and due to this during runtime Python will never look for that variable in any other scope unless you had global
or nonlocal
declaration(Python 3 only) at the top of the function. Note that it doesn't matter if you used variable
before using it with +=
(see the last example), the variable is now local everywhere in the function body.
>>> def plus():
... var += 1
...
>>> dis.dis(plus)
2 0 LOAD_FAST 0 (var)
3 LOAD_CONST 1 (1)
6 INPLACE_ADD
7 STORE_FAST 0 (var)
10 LOAD_CONST 0 (None)
13 RETURN_VALUE
On the other hand, dic[1]
is variable look-up followed by a BINARY_SUBSCR
(same thing for LOAD_ATTR
as well; you can do x.extend([100])
but not x+=[100]
; where x
is a list) and as there are no assignment statements related to dic
after that Python considers it as a either a global variable(LOAD_GLOBAL
) or a free variable(LOAD_DEREF
) and fetches its value from there.
>>> def plus():
var[0] += 1
...
>>> dis.dis(plus)
2 0 LOAD_GLOBAL 0 (var)
3 LOAD_CONST 1 (0)
6 DUP_TOPX 2
9 BINARY_SUBSCR
10 LOAD_CONST 2 (1)
13 INPLACE_ADD
14 ROT_THREE
15 STORE_SUBSCR
16 LOAD_CONST 0 (None)
19 RETURN_VALUE
>>> def plus_with_twist():
var[0] += 1 # this will fail due to the next line
var += 1 # Now `var` is a local variable everywhere in the function body
>>> dis.dis(plus_with_twist)
2 0 LOAD_FAST 0 (var)
3 LOAD_CONST 1 (0)
6 DUP_TOPX 2
9 BINARY_SUBSCR
10 LOAD_CONST 2 (1)
13 INPLACE_ADD
14 ROT_THREE
15 STORE_SUBSCR
3 16 LOAD_FAST 0 (var)
19 LOAD_CONST 2 (1)
22 INPLACE_ADD
23 STORE_FAST 0 (var)
26 LOAD_CONST 0 (None)
29 RETURN_VALUE