Lesson 11 has three parts A, B, C which can be completed in any order.
In this lesson we explain a concept called variable scope. The main idea is that it is possible to have two different variables with the same name whenever they have different scopes. This makes it much easier to write and edit programs, especially large ones.
An example of variable scope
For this example, part of our program will be the following function:
def square(x): value = x * x return valueThis is a function which computes the square of the number
x, for example square(5) returns 25. Now suppose we call square from another part of the program which also uses a tmp variable for another purpose:
# main body of the program starts here value = 17 fivesquared = square(5) print(fivesquared, value)The question is, what will be printed in this scenario? There are two possibilities, if we don’t know how Python works:
- One possibility is that Python recognizes that the two
valuevariables should be “kept separate” somehow. Thus, the call tosquarewill return 25, but the value ofvaluein the main body will stay at 17, and we see the output2517. - The other possibility is that when
square, executes, it over-writes the existing value ofvaluewith 25, and we see the output2525.
Let’s see what actually happens!
We see that Python's behaviour is consistent with possibility #1. In fact, whenever you call a function, you cannot affect any variables defined outside the function. Instead, any statements that assign values to variables affect only a "local" variable which is "inside" the function call. The reason that Python, and most other languages, work like this is that it makes it much more simple to write long programs with many functions. In particular, when we define a new function, we are always allowed to use any variable names (including common ones like result, temp and i) inside the function even if they are being used somewhere else for different purposes.
Illustration
To make this more explicit, we give a table showing the values as they change.
| After this statement: | global values | local values in square(5) |
|||
|---|---|---|---|---|---|
square |
value |
fivesquared |
x |
value |
|
| def square(x): «+2 more lines» | «fnc obj» | ||||
| value = 17 | «fnc obj» | 17 | |||
| «call square(5)» | «fnc obj» | 17 | 5 | ||
| ---value = x * x | «fnc obj» | 17 | 5 | 25 | |
| ---return value | «fnc obj» | 17 | 25 | 5 | 25 |
| print(fivesquared, value) | «fnc obj» | 17 | 25 |
In the table we illustrate three new details:
- The local scope disappears after the function call is finished.
- The way that we apply a function to its arguments is by using local variables! Specifically, when we called
square(5), this is the same as creating a new local scope, adding a variablexwith value5to the local scope, and then executing the body of the function in the local scope. - (The third fact is not related to scope, but is good to know.) The definition of the function square actually is implemented by Python in the following way: a new function object
«fnc obj»is defined, then a variablesquareis defined to be equal to this object. In essence: functions are a special kind of variable.
As usual, you may be interested to see how this looks in the Visualization tool.
x = "outer"
def xReplace(value):
x = value
xReplace("inner")
print(x)
x = value only affects the local version of variable x inside the function. The global version of x does not change. (So, the function xReplace is useless and never has any effect.)Another similar concept to scope is a namespace; a namespace is like a scope for a package. So even if you import a package (such as math) which uses variable name x somewhere, it does not overlap with the variable x used by your program, since they lie in different namespaces.
Scoping Rules: Seeing Out
There are situations where we want to mix variables from local and global scopes. One common example is where you have some common variable initialized once at the start of the program, but you also want your functions to be able to read the variable.
Here, the local scope did not contain a variable named favouriteTopping, but this did not cause an error. Python's rule for evaluating variables is that, if a variable needs to be evaluated which does not exist in the local scope, then it looks for it in the global scope. In our case, it indeed found favouriteTopping in the global scope. (In a more general case with one function body calling another function you would have three scopes; Python always checks the "localmost" first and goes one step at a time to the global scope until the variable is found.)
![]() | Two of the examples above, with orderPizzas and xReplace, are almost syntactically identical. Why does Python create a new local variable x in xReplace, but no new favouriteTopping in orderPizzas? Python's rule is the following: if you only read from the variable, then no new local variable is created; but if you write to the variable even once, then the variable is treated as local throughout the function body. (This is the most common cause of UnboundLocalError: see these two questions [1, 2] in the official Python documentation.) |
Function arguments are always treated as new local variables:
global Changes
Like many other things, the normal flow described above works for 99% of all situations. But that remaining 1% of the time, you really might want to change a global variable from within a function. Python allows you to do this using the global statement. Here's a modification of the earlier xReplace example.
As we mentioned earlier, reading a global variable does not require using the global statement; only writing.
You have now completed this lesson and are ready to move on to the next one.


