[Tutor] global list

Steven D'Aprano steve at pearwood.info
Thu Apr 24 03:00:01 CEST 2014


On Wed, Apr 23, 2014 at 04:46:49PM -0700, Denis Heidtmann wrote:
> In a coursera python course video the following code was presented:
> 
> a = [4,5,6]
> 
> def mutate_part(x):
>     a[1] = x
> 
> mutate_part(200)
> 
> The presenter said something like "a is a global variable, so a becomes
> 
> [4,200,6] after running mutate_part(200)."
> 
> Indeed it does, but why does this work without specifying a as global
> within mutate()?
> My thinking was that an "undefined" error should have been raised.


You only need to define variables as global if you assign to them:

def function(x):
    global a
    a = [1, 2, 3, x]  # assignment to variable "a"

The preferred name for this sort of assignment is "name binding", where 
you bind a value (in this case, the list [1, 2, 3, x]) to the name "a". 
You only need to declare variables as global when you perform a name 
binding on that variable.

Merely retrieving the existing value of a variable doesn't count as 
a binding, and doesn't need to be declared:

# This is okay
def function():
    n = len(a)

# This is not needed
def function(x):
    global len  # Yes, built-in functions are variables too!
    global a
    n = len(a)


and that would be too painful for words.[1]

Now, let's go back to your function:

def mutate_part(x):
    a[1] = x

It looks like a name binding (an assignment) to a, but look more 
closely: you're not actually binding to the name "a", you are binding to 
the item *inside* a. After calling "a[1] = x", a remains bound to the 
same list as before, it is just that the list has been modified 
in-place. So this does not count as a name binding operation, and no 
global declaration is needed.

The same applies to mutating dicts in place, or setting attributes. 
These are all examples of in-place modifications:

    some_dict.clear()
    some_list.sort()
    obj.attribute = 23
    some_dict[key] = value
    del some_list[0]


Only actual assignments to the bare name, including deleting the name, 
need a global declaration:

    some_dict = {}
    some_list = [1, 2, 3]
    obj = something()
    del some_list



[1] For advanced users: built-ins aren't technically "global", they 
actually live in a separate namespace called "builtins" or "__builtin__" 
depending on the version of Python you use. But the principle is the 
same.


-- 
Steven


More information about the Tutor mailing list