This is an archived version of the course and is no longer updated. Please find the latest version of the course on the main webpage.

Variable scope (global variables)

Welcome back! I hope you enjoyed reading the Think Python book. I really like that book. Perhaps I should officially adopt it as our textbook and follow it more closely? 😀 Let me know what you think about that idea!

I also hope you have managed to understand how function stacks work in Python.

Now, this section is going to be a bit confusing. Admittedly, even I have never used what we will be discussing (global variables) in Python. In fact, I have been discouraged from using global variables ever since I studied programming. People always say “global variables are bad”. And not without a reason. It makes it really hard to keep track of, maintain and debug your code. But for completeness, we will just discuss it here. Do not worry if you do not quite get it. You will rarely use it in real life. I will class this topic as something more advanced.

So to recap: local variables are defined inside functions. They can be accessed only inside the functions in which they are declared.

Global variables are defined outside functions. They can be accessed throughout the program by all functions.

Now, we can actually define a function inside another function (not that I have ever done this myself!)

z = 3

def outer_func():
    x = 1
    
    def inner_func():
        y = 2

A namespace is simply a collection of names (i.e. variables) and their assignments. Like the frame in the stack diagram you saw in the Think Python book. [More about namespaces]

  • z is in what is called the global namespace
  • x is in the local namespace of outer_func()
  • y is in the nested local namespace of inner_func()
  • Inside inner_func() we can read and assign a value to y but can only read x and z.

The global keyword will allow you to modify the value of a variable outside the scope of the current namespace.

The rules of variables in functions in Python are:

  • A variable created inside a function is local by default.
  • A variable created outside a function is global (no need to use the global keyword).
  • Use the global keyword to read and write a global variable inside a function.
  • global keyword used outside a function has no effect.

This will make more sense with some examples.

x = 1 # global variable 

def increment(): 
    print (x)      ## 1

increment()

When we are inside increment(), we can read the global variable x, but cannot modify it.

x = 1 # global variable 

def increment(): 
    x = x + 1   # Error. Cannot compute x+1 since we have not defined x
    print (x)

increment()     

But if we use the global keyword, x can now be modified from inside increment().

x = 1 # global variable 

def increment(): 
    global x
    x = x + 1   
    print (x)  # 2

increment()     
print(x)       # 2

When there are several variables with the same name, Python chooses the variable closest to its scope. More specifically, it:

  1. checks the local variables in function
  2. checks the local variables in the enclosing function
  3. checks global variables
  4. checks built-in variables

For example, try to guess the output of the following program, and then verify it.

def outer_func(): 
    a = 20 
    def inner_func(): 
        a = 30 
        print(a)
    inner_func() 
    print(a)
a = 10
outer_func() 
print(a)

The output should be 30, 20, 10. The variables are all defined in separate namespaces.

Here is another example.

def outer_func(): 
    global a
    a = 20 
    def inner_func(): 
        global a
        a = 30 
        print(a)
    inner_func() 
    print(a)
a = 10
outer_func() 
print(a)

This time, the output is 30, 30, 30. Thne a in all functions point to the single global variable.

A final example.

def outer_func(): 
    a = 20 
    def inner_func(): 
        global a
        a = 30 
    print(a)
    inner_func() 
    print(a)
outer_func() 
print(a)

The output should be 20, 20, 30. The variable a is only declared global inside inner_func().

Hopefully you can see how dangerous this can be if you do not fully understand how global variable works. Any function will be able to modify a global variable, and this makes it hard to figure out which function was responsbile for modifying the variable. I personally recommend keeping all variables local and just pass any needed variables into the functions as arguments to the function. This will avoid what is known as side-effects.