Here’s another article in the Functions in Python series, about local and global variables.
If you haven’t read the previous parts yet, feel free to do so. Here they are:
6) Mutable Optional Parameters
8) Arbitrary Number of Positional Parameters
9) Arbitrary Number of Keyword Parameters
10) Arbitrary Number of Both Positional and Keyword Parameters
11) Nested Functions
12) Calling Functions in Other Functions
13) Assigning Functions to Variables
15) Functions Returning Functions
Today we’ll be talking about variable scopes, about local and global variables. You can also read this article on scopes if you want.
Variables may have different scopes. A scope of a variable is the part of the program where it can be accessed and used. If a variable has global scope, it’s accessible anywhere in the program. If a variable is accessible only in a function, it has local scope – the function body is its scope. Local scope means that it’s not available outside the function.
Variables can be used only after they are defined. If you try to use a variable that hasn’t been defined, you’ll get an error. Here’s an example where we’re trying to use a variable which is hasn’t been defined yet:
print(city)
city = "New Orleans"
Here’s what we get:
NameError: name 'city' is not defined
Let’s have a look at the following code:
def read_value():
print("name = ", name)
age = 28
def nested_read_value():
print("name = ", name)
print("age = ", age)
nested_read_value ()
name = "Mr. Global"
read_value()
Here’s the output:
name = Mr. Global
name = Mr. Global
age = 28
Here we have the variable name in global scope and the variable age in the function read_value. The function body has access to the variable name, which is in global scope. Even the function body of the nested function nested_read_value has access to that variable. The nested function also has access to the variable age, which is defined in the enclosing function.
So, the functions deeper in hierarchy have access to all the variables defined higher in the hierarchy. Here, having access means being able to reference the value of the variable, but not changing its value. If we try to change the value of a global variable inside a function, we actually create a new local variable with the same name, and this will be described in a mo.
Here’s a simple illustration of how scopes work:
So, the nested function nested_read_value is inside the enclosing function read_value, which in turn is inside the program, so inside the global scope. First the black arrows. They show that the nested function is available in the enclosing function, but not in global scope (hence there’s no arrow from the nested function to global scope). The enclosing function is available in global scope. Now the variables: the global variable name (in red) is available, so can be referenced, in the enclosing function as well as in the nested function. The variable age (in green), which is defined locally in the enclosing function, is also available in the nested function, which is deeper in the hierarchy, but not in global scope.
As long as the variables have different names, everything’s fine. But there may be several variables with the same name and then it’s very important to know their scopes.
In Python variables are local if not otherwise declared. So, if we define a variable inside a function, it’s not available outside it, even if it has the same name. You can modify the variable in the function and it will have no effect on the variables in global scope. For brevity we call variables with global scope global variables and those with local scope, local variables.
Let’s define a variable in a function and then try to use it outside the function:
def pluralize(number):
noun = "cat"
print(str(number) + " " + noun + "s")
pluralize(3)
print(noun)
Here we have a variable called noun in the function. In the last line of the code we are trying to print its value, but it turns out that it’s impossible. That’s what we get:
NameError: name 'noun' is not defined
The error is due to the fact that noun is only known locally, in the function. For the rest of the code it just doesn’t exist.
Now let’s have a look at the following code:
def pluralize(number):
noun = "cat"
print(str(number) + " " + noun + "s")
noun = "dog"
pluralize(3)
print(noun)
Here we have a variable called noun in two places: one in the function body, one outside the function. In the function body noun is assigned “cat”, outside the function noun is assigned “dog”. So we can say we have a global variable noun, which is available globally, anywhere in the code, and a local variable noun, which is defined and available only in the function. Actually, the global variable noun is also available in the function body, so the function has access to two variables with the same name. Which one does it choose? By default it chooses the local one.
Let’s check out the output:
3 cats
dog
As we can see, the output from the function call pluralize(3) is 3 cats, not 3 dogs, which means the function used the local variable, defined in it.
Below the function call we have one more line of code, where the print(noun) function is called and the output from it is ‘dog’, which means it takes the global noun variable as its argument. And this is quite clear, because outside the function the print function doesn’t have access to the local variable.
Now, what happens if we only have the global variable? Let’s remove the local one:
def pluralize(number):
print(str(number) + " " + noun + "s")
noun = "dog"
pluralize(3)
print(noun)
Now the output is:
3 dogs
dog
So, this time the function doesn’t have to choose between the local and the global variable, because there’s only one and it’s accessible all throughout the code, also inside the function body.
Now, let’s make the program “think” harder. Here’s our next code snippet:
def pluralize(number):
print(str(number) + " " + noun + "s") # first print call
noun = "cat"
print(str(number) + " " + noun + "s") # second print call
noun = "dog"
pluralize(3)
print(noun)
Here’s what we get when we run the program:
UnboundLocalError: local variable 'noun' referenced before assignment
We get an error!
In the first line with print in the function the variable noun is used, but the function can “see” that the variable is defined below, still inside the function body. If the function can choose, it will always choose the local variable, which is also the case here. The problem is we are trying to use the variable in the first print call, where it is still undefined. The function could use the global variable in the first print call, and it would if there were no local variable also defined. But here the function has two variables to choose from and the local one always wins. Python just doesn’t allow a global and a local variable with the same name to be in the same scope.
However, we could make the function use the global variable in the first print call, but we would have to explicitly use the keyword global. This must be done in the function body before the variable is used. Here’s how:
def pluralize(number):
global noun
print(str(number) + " " + noun + "s")
noun = "cat"
print(str(number) + " " + noun + "s")
noun = "dog"
pluralize(3)
print(noun)
Here’s the output:
3 dogs
3 cats
cat
Now, an interesting thing happened: After the function returned, the last print function, which is outside the function and has access to global variables only, printed “cat”. This is because when we use the global keyword in the function, we start using the global variable, and by assigning “cat” to noun inside the function body, we actually assign it to the global variable.
We could even use the global keyword to define a global variable inside a function. Here’s an example:
def variable_maker():
global x
x = 5
variable_maker()
print("A variable was created: x =", x)
By calling the function variable_maker, we create the global variable x. If we run the program, we don’t get the error telling us that x is not defined:
A variable was created: x = 5