# Global Variables ([home](https://github.com/alexhkurz/introduction-to-programming/blob/master/README.md) ... [previous](https://hackmd.io/@alexhkurz/HyccPGbJv) ... [next](https://hackmd.io/@alexhkurz/SkIGSnPTU)) (this material was more difficult than I had anticipated and it took us three sessions to go through it) In the last session, we learned how to understand the execution of the recursive program `fib` as traversing a tree in which the nodes are labelled with recursive calls to the function `fib`. In particular, for `n=6`, we worked out everything in detail. But for larger values of `n`, printing out the whole tree would not help our understanding of the situation. Instead it makes sense to explore just how many nodes are in the tree. Or, in other words, how often is the function `fib` called? One way to do this is to use a **global variable** that counts how often the function `fib` is called. To understand the concept of a global variable, it makes sense to first explain what is meant by the scope of a variable. ## The Scope of a Variable Let us look at n=6 def fib(n): if n==0: return 0 elif n==1: return 1 else: return fib(n-2)+fib(n-1) print(fib(n)) **Activity:** - How many occurrences of the name `n` are in the program above? - In the program above, if we change in the line `n=6` the name of `n` to, say, `input`, which other occurrences of `n` do we need to change so that we still have the same program? - In the program above, if we change in the line `def fib(n):` the name of `n` to, say, `k`, which other occurrences of `n` do we need to change so that we still have the same program? The variable `n` in the function `fib` is a **local variable**. This means that the name `n` is not known outside of the function `fib`, or, more precisely, that the variable `n` in `n=6` is different from the variable `n` inside `fib`. To explain this better, we use the notion of the **scope** of a variable. The scope of the `n` in `fib(n)` is the definition of the function. The scope of the `n` in `n=6` is the whole program with the exception of the definition of `fib(n)`. Since Python forces us to indent the code in the definition of `fib(n)`, we can distinguish the scope of the two different variables called `n` easily. The scope of the variable `n` inside the function `fib` is everything that is indented. To summarize the discussion so far: - What we need to be careful about is that in the program above there are two different variables that happen to have the same name `n`. - One is only "visible" "inside" the function, the other is only visible outside. - One says that the `n` of `fib(n)` **shadows** the `n` of `n=6`. Why do we want that the variables inside a function are new, fresh variables that are not visible on the outside? - First, in large programs that makes it easier for programmers to write functions that do not depend in unexpected ways on the names of variables chosen outside of the function. - Second, the recursion only works if for each call of `fib(n)`, the `n` are fresh variables that can have different meanings. The last point should become clear by looking at the call tree fib(6) / \ fib(4) fib(5) / \ / \ ... ... again: The value of `n` in `fib(n)` changes for each call. So each time we call `fib(n)` we make a new, fresh variable named `n` and all these different variables can be instantiated with different values (such as $6,4,5$ above). ## Global Variables If a variable is defined outside of a function but visible also inside the function, it is called a global variable. Why would one want global variables? For example, if we want to count how often `fib(n)` is called, it makes sense to do this by incrementing upon each call a global variable that has the same meaning in each of the calls (the how-manyeth call the current call is). But before we look at this in detail, let us illustrate the scope of global variables with the program [loc_glob_var.py](https://github.com/alexhkurz/introduction-to-programming/blob/master/src/loc_glob_var.py). n=1 def f(): n=2 print(n) print(n) f() print(n) **Activity:** Run the code above. Which three values does it print? Why? Change the name of the variable in the definition of `f()` from `n` to some other name. Does the behaviour of the program change? **Activity:** Compare the Python program above with the C program [loc_glob_var.c](https://github.com/alexhkurz/introduction-to-programming/blob/master/src/loc_glob_var.c) listed below. We only made the obvious changes required by C, in particular, we added the standard input output (`stdio`) library for printing, we added declarations such as `int` and `void`, we added semicolons after all statements, we changed `print` to `printf` and added a control string `"%d\n"` as the first argument of `printf` and, finally, we also put the code that should be executed in a `main` function. # include <stdio.h> int n = 1 ; void f(){ int n = 2 ; printf("%d\n",n) ; } int main() { printf("%d\n",n) ; f() ; printf("%d\n",n) ; } With linux and mac [^windows] you can compile this program with gcc loc_glob_var.c and run it with ./a.out What output does this program produce? **Activity:** In the previous activity, we have seen that the Python and the C program, despite looking very similar, produce different outputs. Now we want to understand why this is the case and how to modify the Python program so that it behaves like the C program and vice versa. The results of the activity above are available as [loc_glob_var2.py](https://github.com/alexhkurz/introduction-to-programming/blob/master/src/loc_glob_var2.py) and [loc_glob_var2.c](https://github.com/alexhkurz/introduction-to-programming/blob/master/src/loc_glob_var2.c). **Activity:** Modify the program [recursive_fib.py](https://github.com/alexhkurz/introduction-to-programming/blob/master/src/recursive_fib.py) so that it prints out the number of calls to the function `fib`. [Hint: (1) Compare this task to printing `n` from the session on the [call stack](https://hackmd.io/@alexhkurz/rJjfXqS08). (2) Use a global variable to count how often `fib` is called.] **Activity:** How fast does the number of calls to `fib` grow with the number `n` in `fib(n)`? ## Further Reading [Programiz: Python Global, Local and Nonlocal variables](https://www.programiz.com/python-programming/global-local-nonlocal-variables) [GeeksforGeeks: Global and Local Variables in Python](https://www.geeksforgeeks.org/global-local-variables-python/) ## References [The Python Language Reference: The `global` statement](https://docs.python.org/3.8/reference/simple_stmts.html#global) [The Python Language Reference: Execution model](https://docs.python.org/3.8/reference/executionmodel.html) [^windows]: I don't know how to do this with Windows. I tried but lost patience after 15 minutes ... I am sure it is easy enough to do for a Windows person ...