- global scope
Variables and function names are identifiers (and in future you'll learn about other kinds of identifiers). Scope is the area of the source code where an identifier is accessible (can be used).
A variable created outside of functions has global scope. It's accessible within code that's located anywhere, including inside of functions' bodies. (Of course, except for the cases when the call happens earlier than variable's definition). Here's a simple example:
def gen_title(name): return manner + " the " + name manner = "Her Majesty" print(gen_title("Pumpkin"))
Her Majesty the Pumpkin
The function utilizes two identifiers: its own parameter
name and a globally-scoped variable
manner. The value of
manner is read at the time of the call. Since variables can be redefined, another call may end up reading a different value:
def gen_title(name): return manner + " the " + name manner = "Her Majesty" print(gen_title("Pumpkin")) manner = "Her Excellency" print(gen_title("Boop"))
Her Majesty the Pumpkin Her Excellency the Boop
Function names are also globally-scoped identifiers. The only way to use a function name identifier is to call the function1. So, a call may be contained in a body of another function. Below,
gen_title contains a call to
def gen_cute(word): return "Little Cutey " + word def gen_title(name): return manner + " the " + gen_cute(name) manner = "Her Majesty" print(gen_title("Pumpkin"))
Her Majesty the Little Cutey Pumpkin
At this point you may be wondering why is this even worth discussing. Variables and functions can be used anywhere, so?.. Well, there exist other cases where the scope of an identifier is not global. The next lesson will explain one. And in the next courses you'll encounter more syntactic structures with limited scope.
Our examples above were rather plain, so let's work on a real problem to further illustrate globally-scoped variables. The task is to calculate the number of months passed between some year and the current year. Open a new repl and write a function
months_since which takes a year as an argument, and returns the number of months between that year and the current year. You need to store the current year as a separate global variable.
Your solution might look like so:
current_year = 2020 def months_since(year): return (current_year - year) * 12 print(months_since(2003)); # →◼ 204
current_year is globally-scoped, you can write other functions which also use that variable. For example, let's add a
def weeks_since(year): return (current_year - year) * 52 print(weeks_since(2003)); # →◼ 884
def weeks_until(year): return (year - current_year) * 52 print(weeks_until(2031)); # →◼ 572
Now go ahead and, in addition to those 3 functions, write two more:
years_until_abba100which calculates how many years left until 100th anniversary of ABBA, a Swedish pop supergroup formed in Stockholm in 1972 by Agnetha Fältskog, Björn Ulvaeus, Benny Andersson, and Anni-Frid Lyngstad 💃🕺.
months_until_halleywhich calculates how many months left until Halley's comet returns to our solar system in 2061.
Having a common variable outside of functions is fine in small programs. But as soon as your program reaches a few dozen lines, problems might arise:
- It's hard to read the code because you have to jump between three places: variable creation, function definition and function call.
- It's hard to make sure the variable's value was not changed in between the calls, intentionally or by mistake.
- Functions have additional dependencies. Dependencies often lead to difficult bugs.
Try to write functions that only take values via arguments, but not by accessing external variables from the body. This way you, the programmer, have more control. Bugs are still possible, but they'll be easier to fix.
The described properties of scope are specific to Python and the majority of mainstream programming languages. There exist other languages (e.g. Haskell, Eiffel, Newspeak) where scope is more limited and strict. In some of them it is impossible for a function to access outer variables, for example.
- Function's body is an isolated scope inaccessible from outside.
returntransports a value, but does not affect the scope.
For now. In future, you'll learn about an advanced use-case: using a function name identifier as if it were a variable.