I would like to know details about why this doesn't work as expected:
def outer():
    mylist = []
    def inner():
        mylist += [1]
    inner()
outer()
Especially because mylist.__iadd__([1]) works fine.
Any variable assigned to is assumed to be of local scope.
To assign to a global variable you do:
global var
var = 5
You can't do quite what you're doing in Python 2, but in Python 3 you can do:
nonlocal mylist
mylist += [1]
The Python 2 alternative for changing an item or attribute of something is
def outer():
    mylist = []
    def inner(mylist = mylist):
        mylist += [1]
    inner()
outer()
If you want to replace the value of the variable, you need to:
def outer():
    def setlist(newlist):
        mylist = newlist
    mylist = []
    def inner():
        setlist(['new_list'])
    inner()
outer()
                        The problem is that when you assign to a variable name inside a function, Python assumes you're trying to create a new local variable that will mask a similarly-named variable in outer scope. Since += has to get the value of mylist before it can modify it, it complains, because the local version of mylist isn't yet defined. MRAB's answer gives a clear explanation of the semantics.
On the other hand, when you do mylist.__iadd__([1]), you aren't assigning a new variable name inside the function. You're just using a built-in method to modify an already-assigned variable name. As long as you don't try to assign a new value to mylist, you won't have a problem. For the same reason, the line mylist[0] = 5 would also work inside inner if the definition of mylist in outer were mylist = [1].  
Note however that if you do try to assign a new value to mylist anywhere in the function, mylist.__iadd__([1]) will indeed fail:
>>> outer()
>>> def outer():
...     mylist = []
...     def inner():
...         mylist.__iadd__([1])
...         mylist = []
...     inner()
... 
>>> outer()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 6, in outer
  File "<stdin>", line 4, in inner
UnboundLocalError: local variable 'mylist' referenced before assignment
If you want to assign a new value to a variable from a containing scope, in 3.0+ you can use nonlocal, in just the way you'd use global to assign a new value to a variable in global scope. So instead of this:
>>> mylist = []
>>> def inner():
...     global mylist
...     mylist += [1]
... 
>>> inner()
>>> mylist
[1]
You do this:
def outer():
    mylist = []
    def inner():
        nonlocal mylist
        mylist += [1]
    inner()
    print(mylist)
outer()
                        If a name is bound (a variable is assigned) in a function then that name is treated as local unless it's declared global.
Thus in inner, mylist is local.
When you write x += y, at runtime Python will try:
x = x.__iadd__(y)
If that fails, Python then tries:
x = x.__add__(y)
                        If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With