Question: I'm learning about scope in Python 3, and this example has me confused. Comparing behaviors of a list variable and a string variable when called inside a function:

```
foo1 = []
foo2 = ''
def f():
    foo1.append(3)
    global foo2
    foo2 += 'c'
    print('foo1-in-f:',foo1)
    print('foo2-in-f:',foo2)

print('foo1-before:',foo1)
print('foo2-before:',foo2)
f()
print('foo1-after:',foo1)
print('foo2-after:',foo2)

```

The output, as expected, is:

```
foo1-before: []
foo2-before:
foo1-in-f: [3]
foo2-in-f: c
foo1-after: [3]
foo2-after: c

```

I'm confused why the **string** must be **declared global**, as in the line `global foo2`, but the **list** is **not declared global**, as in there in no line `global foo1`.

I ran the code omitting the line `global foo2` and unsurprisingly got `UnboundedLocalError: local variable 'foo2' referenced before assignment`. But, why am I not getting this error for `foo1`?

Any insights appreciated. I want to make sure I'm understanding how this really works.

Answer: 
In a Python function, all variable references are **assumed to be global** unless named locally. All new objects are **created in local scope** and there are restrictions on transferring or modifying objects to another scope.

You can do:

```
a=1
def f(): return a+1      # unnamed integer object created and returned

>>> f()
2

```

You can modify the contents of a global mutable variable since this does not assign a locally named object to the global scope:

```
ls=['string']
def f():
    ls.append('another')  # unnamed string object created and added to ls
    ls[0]+='_modified'    # ls[0] read, new object created with +=, 
                          # new object added to ls[0]   

>>> f()
>>> ls
['string_modified', 'another']

```

But it would be an error to use `ls+=[something]` since the assignment `+=` is treated as `ls` being local in scope then reassigned to the global scope:

```
ls=[]
def f():
    ls+=['new entry'] # UnboundLocalError

```

The issue you are seeing is not necessarily modifying global variables. It is with reassigning the name that the function has used locally to the global scope.

There is a [FAQ on this issue](https://docs.python.org/3/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value) on the Python website.

There is an [expanded FAQ](https://eli.thegreenplace.net/2011/05/15/understanding-unboundlocalerror-in-python/) on Eli Bendersky's blog.
You need to know how variable scopes work in Python. Python does not require you to declare variables, but assumes that a variable assigned in the body of a function is local. You can see this reflected by the compiler in the generated bytecode:

```py
foo1 = []
foo2 = ''
def f():
    foo1.append(3)
    foo2 += 'c'

from dis import dis
dis(f)

```

```
  4           0 LOAD_GLOBAL              0 (foo1)
              2 LOAD_METHOD              1 (append)
              4 LOAD_CONST               1 (3)
              6 CALL_METHOD              1
              8 POP_TOP

  5          10 LOAD_FAST                0 (foo2)
             12 LOAD_CONST               2 ('c')
             14 INPLACE_ADD
             16 STORE_FAST               0 (foo2)
             18 LOAD_CONST               0 (None)
             20 RETURN_VALUE

```

`foo1` is loaded from the global context because `foo1.append(3)` is an item assignment operation - it modifies the actual reference. AFAIK Python strings are immutable which means that you need copy the value before doing the assignment, which is what you are doing inside the function because `foo2 += 'c'` will actually create a new string. Try running `foo1 += [3]` and you will get the same `UnboundLocalError` for `foo1`.

`foo1.append(3)` is an item assignment operation which is equivalent to `foo1[len(foo1):] = [3]`. This kind of operation is not possible for Python string for reasons stated above - try running `foo2[:] = 'c'` and you will get the error `'str' object does not support item assignment`.

Now, the global keyword basically tells the interpreter to treat `foo2` as a global variable in spite of the assignment within the function.