Python language basics 33: variable shadowing and the ‘global’ keyword
July 26, 2015 1 Comment
Introduction
In the previous post we looked at positional and keyword arguments in a function. We saw how positional arguments were matched up with the arguments in the function signature. We also discussed how keyword arguments could make your code cleaner by explicitly providing the argument names in a function call.
In this post we’ll look at how a variable declared within a function can overshadow another variable declared outside of it.
Variable scope
Variable scope means the bounded location in the code where a variable can be used and has a meaningful value. The most prevalent scope type is local. Locally scoped variables are used within a function. We’ve seen examples of that before:
def get_integer_input(prompt_text): user_input = input(prompt_text) return int(user_input)
The variables “prompt_text” and “user_input” are both local variables that can be accessed within the get_integer_input method. They cannot be accessed outside this function:
def get_integer_input(prompt_text): user_input = input(prompt_text) return int(user_input) print(user_input)
The above code won’t compile as user_input is not defined at that level.
Variables can of course be declared on a higher level called global scope:
user_input = 10 def get_integer_input(prompt_text): user_input = input(prompt_text) return int(user_input) print(user_input)
The user_input variable in the first line has global scope and the print statement will print “10”. The local user_input variable within get_integer_input has nothing to do with user_input declared globally just before. To prove this we’ll extend the code slightly:
user_input = 10 def get_integer_input(prompt_text): user_input = input(prompt_text) print(user_input) return int(user_input) int_input = get_integer_input("Provide a number: ") print(user_input)
If you run the above code and enter e.g. 40 as the input on line…
user_input = input(prompt_text)
…then the print statements will give 40 and 10. The global user_input variable has been unaffected by the local user_input variable declaration and assignment.
If you use PyCharm then you’ll see a gray squiggly line underneath user_input in the get_integer_input function. If you hover over the variable you’ll see the reason: shadows name ‘user_input’ from outer scope. So user_input in get_integer_input shadows the globally declared user_input variable.
Note that there’s nothing wrong with this in a programmatic sense. The code compiles and runs and it may well have been your intention to introduce a local variable with the same name as that of a global variable. The message in PyCharm is just a safety check: did you really mean to shadow another variable or are you referring to the the global variable? In case you meant to reference the globally declared variable and change its value within the get_integer_input then the “global” keyword comes to the rescue:
user_input = 10 def get_integer_input(prompt_text): global user_input user_input = input(prompt_text) print(user_input) return int(user_input) int_input = get_integer_input("Provide a number: ") print(user_input)
Running the code with 40 as the user input will also change the value of the globally declared user_input variable to 40. The print statements will print 40 and 40 accordingly.
Read the next part here.
Read all Python-related posts on this blog here.
Thanks, this was really useful.