# 11B: Variable Scope

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. It is also a necessary ingredient in a later topic, recursion.

## An example of variable scope

For this example, part of our program will be the following function:

```def square(x):
value = x * x
return value```
This 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 `value` 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:

1. One possibility is that Python recognizes that the two `value` variables should be "kept separate" somehow. Thus, the call to `square` will return 25, but the value of `value` in the main body will stay at 17, and we see the output `25 ``17`.
2. The other possibility is that when `square`, executes, it over-writes the existing value of `value` with 25, and we see the output `25 ``25`.

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 inside the function (including common ones like `result,` `temp` and `i`) even if they are being used somewhere else for different purposes.

To see this in detail, look at "Step 6 of 8" in the visualizer. Notice that there are two different `value` variables: one inside of the `square` function, and one outside (in the "global" area).

Multiple Choice Exercise: Inner and Outer
What is the output of the following program?

`x = "outer"def xReplace(value):   x = valuexReplace("inner")print(x)`
Correct! The statement `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.

Example
Reading a global variable from inside a function

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, as the following broken code fragment illustrates (it attempts to reset the variable `g` to `0`, but fails).

## `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. Note that we declaring the variable as `global` in the function. This lets you change the global value from within the function.

Reiterating: when inside of a function, assigning to a variable name defined at global scope actually creates a separate new local-scope variable with the same name, instead of modifying the global-scope variable (like `resetToZero`). If you want to update the global-scope variable, you must include the statement `global «variable-name»` inside of the function (like the fixed `xReplace` example). Then Python understands that changes to `«variable-name»` in the function are meant to refer to the existing global-scope variable.

As we mentioned earlier, reading a global variable does not require using the `global` statement; only writing. That concludes the lesson!