Python Variable Scope

Outside Resources:

TheNewBoston – Python Variable Scope

Scope Definition with Examples


If you have global variables and functions in the same program, you might be seeing some confusing bugs and errors if you don’t understand variable scope.

Here’s the short explanation:

  • Variables defined inside a function are local variables – they disappear from memory after the function finishes executing.
  • Variables declared outside a function are global – they can be seen from anywhere in the program.
  • Functions cannot reassign a global variable unless you specifically enable them to be changed by the function using “global” keyword.
  • You can have a local variable and a global variable with the same name, but they are two distinct variables with separate stored values.

Global variables can be seen from anywhere in your program.

If you define a variable outside of a function (not indented at all), it is global.

#global variable named score
score = 10

If you ran that simple program and then typed score into your Python window (console), it would tell you that score is 10.

Local variables only exist within a function; after the function finishes being called, they disappear from memory.

def my_function():
    #local variable defined in function
    score = 3

Problems You’ll Encounter

Try this to see some problems you might run into:

score = 0

def get_points()
    score = 10

get_points()
print(score)   #This prints 0

You can call the get_points() function, but when you print score, it’s still zero.

What happened? It’s because there are two separate variables called score. The first one is a global variable, and the one inside the function is a local variable that exists independently. If you print  score from inside the function, it will equal 10. Then that local variable disappears. Meanwhile, the global variable is equal to zero the whole time.

Now try running this program:

#define function with local variable
def my_function():
    score = 3

#call the function in main program
my_function()

#try to print the score variable
print(score)     #error: name 'score' not defined

Printing score from the main program won’t work, because score is a local variable that doesn’t exist in the main program.

In other words, score doesn’t have a global scope in this example.

Now try this example:

score = 0

def add_points(n):
    #use += to assign new value to score - gives error
    score += n 

add_points(5)
add_points(12)

print(score)

If you run that example, you might expect a score of 17 to be printed. But it doesn’t work. It says “local variable score referenced before assignment.” Python is assuming that you don’t want to assign to a global variable, so it also assumes that score, inside add_points(), is a local variable.

You’d get the same error from the following one line program. It doesn’t know a previous value of score (none is defined), so it can’t calculate score+1.

score += 1

Why does Python behave this way???

If we use a lot of global variables in a large program, we can accidentally use the same variable name (e.g.  “i”), in different places for different reasons. That causes bugs: one part of the code changes the global variables’ value in a way that breaks another part of the code.

Using local variables instead allows you to reuse variable names in various functions in a way that doesn’t allow them to break each other.

Assigning vs Read / Compare

Python can actually read a global variable or compare to it. This doesn’t cause the bug problems in the previous paragraph, because merely reading a value doesn’t break another part of the program that needs to use the same variable.

You could have a global counter variable and check if it’s greater than 10, for example.

However, Python doesn’t allow you to assign new values to global variables unless you tell it that you really want to do that.

“global” Keyword

In this example, we have two functions that can both change the value of the score variable, because they used the global keyword inside the function before assigning to score.

score = 0

def addpoints(n):
    global score      
    score += n

def removepoints(n):
    global score
    score -= n

addpoints(8)
removepoints(5)

print(score)    #prints 3 as expected

If you use a lot of global variables in a lot of functions, you’ll find that you are stuck writing a lot of extra lines of code using the global keyword … hopefully that gets annoying enough to make you rethink your code and eliminate the use of global variables.

There are some reasons you often want to avoid using avoid global variables. They can cause bugs if you accidentally reuse a name, and they reduce the reusability of your code.

Sometimes people misunderstand how the global keyword works and try things like this:

global score = 0  #Wrong use #1

def x():
    global score = 10 #Wrong use #2

Wrong use #1: You don’t need to use global in the main program (non-indented code that’s outside of function definitions), because variables created out there are already global.

Wrong use #2: Inside the function above, you need a separate line that just says “global score” and then “score = 10” in the next line.

Alternatives to Global Variables / Global Keyword

Programmers tend to avoid global variables. They can cause bugs, and they also make your code less adaptable for new purposes.

Alternative #1: pass values into functions (arguments / parameters) and have your functions return values.

(See Python Functions – includes arguments  / parameters)

Example:

def game():
    score = 2
    score = addfive(score)
    print score

def addfive(s):
    return s + 5

The game() function represents a “main” function for a program, and this would call a variety of outside functions. It uses a local variable for score.

When another function needs to know the score, game() sends it to that function as an argument. Notice “addfive(score)” – this is a function call that sends score to the addfive() function.

The addfive() function receives a parameter called s. This is an input to the addfive() function. In this case, the input is whatever the value of score was from game(). If you send a value of 2 (as was done above), then s=2 inside the addfive() function.

The “return s + 5” command sends an output value back to the part of the program that called addfive() in the first place.  Since s+5 = 7, the function returns a value of 7 to the other program.

Therefore, “score = addfive(score)” becomes “score = 7” after the addfive() function finishes and returns a value.

Alternative #2: Create an object with its own variable (attribute).

This opens a big , awesome can of worms: Object Oriented Programming (OOP).

class game():   #define a new type of object
    pass

mygame = game()   #create a game object named mygame
mygame.score = 0  #give mygame a score attribute

def points(g, n):
    g.score += n

addpoints(mygame, 100)
print mygame.score

Now we have a function that receives a game object and adds points to that game object’s score.

Alternative: you can also use a global dictionary instead of an object. You can change dictionaries from within a function, and dictionaries are easier to learn.

[Full explanation of this example is omitted, because it would be long.]

There is way more to say about this! Just know that you can use objects to avoid using  global variables, among many other benefits.

“Alternative” #3: Just use global variables (for now).

For new programmers who are just learning how variables and functions work together, it is okay to use global variables.

As you get more advanced, keep pushing yourself to learn new concepts (including parameters, returns, objects, classes, etc).

As your programs get larger and more complex, you might get the feeling that your code is overly tedious and bug prone and difficult to modify or reuse, and that there’s probably a better way to do it. Those are great moments to refactor your code, which means rewriting it to do the same thing, but in a way that makes the code easier to work with.