(This Gist can be accessed at http://goo.gl/ZYAZkC.)
In Python we use variable to refer to objects. In other words, a variable is a name for an object.
This Gist is an explanation of how Python creates variable names, and how it decides what object a variable name refers to.
Python uses scopes to keep track of variable names. A scope is a mapping from 'variable name' to 'object that name refers to.' (Technically, it's a mapping from 'variable name' to 'reference to object that name refers to', since object exist independently of the names we give them.)
TODO(jasonpr): Put a picture!
When you write an assignment statement, koalas_in_back_yard = 50
, Python adds an entry to a scope that points the name koalas_in_back_yard
to an object, 50
. But, how does Python decide which scope should receive that entry?
If your assignment statement is written outside of all function definitions, then assignments affect the global scope. The global scope is created when you start the Python shell, and stays around for the duration of your session.
If your assignment statement is written inside of a function definition, then assignments affect a local scope (i.e. a function scope). Every time the enclosing function is run, Python creates a fresh scope for that function. When the function completes (say, when it is return
ed from), the local scope is destroyed. (Read about closures if you want to learn about zombie-like local scopes that stick around after their function returns!)
Let's add one variable to the global scope, and make a function with a local variable, too. When you run this example, you should speculate about how Python was able to find the global variable fav_rapper
inside of a function.
fav_rapper = 'Eminem'
def print_favorites():
print 'Favorite rapper:', fav_rapper
fav_person = 'Shakira'
print 'Favorite person:', fav_person
print_favorites()
Output:
-> Favorite rapper: Eminem
-> Favorite person: Shakira
When we ask Python to lookup a variable, Python must decide which scope(s) to look in.
If we are not in a function, Python always looks in the global scope. If it can't find the variable name, it gives up! If we are in a function, Python looks inside the local scope. If it finds the variable name, then it declares success and uses the object associated with that name. But, critically, if it can't find the name in the local scope, it tries the global scope next. Only if the name is also missing from the global scope does Python give up.
fav_color = 'green'
def tell_me_about_jimmy():
name = 'James Smith'
fav_color = 'fuchsia'
print name + "'s favorite color is", fav_color
tell_me_about_jimmy()
print 'My favorite color is still', fav_color
Output:
-> James Smith's favorite color is fuchsia
Every function is called, Python builds up a new local scope for that function. Here's how it works:
- Create a totally empty scope.
- Make an entry in the scope for every parameter name. Each parameter should point to the object that was supplied as an argument.
- Scan through the code, without executing any code yet. Look for all variable names in the body of the function that get a value assigned to them. (In the
introduce_person
function, we find just one--punctuation
.) Add these names to the scope, but make note that we don't know their associated objects, yet. We will add in their objects when we actually execute the assignment statement.
At this point, the scope is built, and the body of the function can be executed.
Below, we can see that the name fav_car_maker
is added to the local scope for calls of introduce_person
. When it's looked up in the function's print
statement, the local scope is checked first. That's how the parameter is correctly looked found.
fav_car_maker = 'Tesla'
def introduce_person(name, fav_car_maker):
punctuation = "!"
print name + "'s favorite car maker is", fav_car_maker + punctuation
introduce_person('Brandon', 'Ford')
introduce_person('Carlos', 'Audi')
print 'My favorite car maker is still', fav_car_maker
-> Brandon's favorite car maker is Ford!
-> Carlos's favorite car maker is Audi!
-> My favorite car maker is still Tesla
In step 3 above, Python adds some names to the scope... even before those names are first assigned to! If we try to resolve a name that doesn't yet have a value, Python will not be happy:
conflicting_name = 123
def mess_with_conflicting_names():
print conflicting_name
conflicting_name = 456
mess_with_conflicting_names()
It doesn't work! We get the following error message:
Traceback (most recent call last):
File "scope.py", line 7, in <module>
mess_with_conflicting_names()
File "scope.py", line 4, in mess_with_conflicting_names
print conflicting_name
UnboundLocalError: local variable 'conflicting_name' referenced before assignment
Many operations bind a name.
- Assignments:
jasons_study_hours = [3, 2, 0, 8, 1]
bindsjasons_study_hours
. - Function definitions:
def get_money(): ...
bindsget_money
. - Passing parameters:
introduce_person('Bob', 'BMW')
bindsname
andfav_car_maker
. - Import statements:
import string
bindsstring
. - For more, see https://docs.python.org/2/reference/executionmodel.html.