11.8. Variable Scope

The scope of an identifier is defined to be the portion of the program where its declaration applies, or what we refer to as “variable visibility.” In other words, it is like asking yourself in which parts of a program do you have access to a specific identifier. Variables either have local or global scope.

11.8.1. Global vs. Local Variables

Variables defined within a function have local scope, and those which are at the highest level in a module have global or nonlocal scope.

In their famous “dragon” book on compiler theory, Aho, Sethi, and Ullman summarize it this way:

“The portion of the program to which a declaration applies is called the scope of that declaration. An occurrence of a name in a procedure is said to be local to the procedure if it is in the scope of a declaration within the procedure; otherwise, the occurrence is said to be nonlocal.

One characteristic of global variables is that unless deleted, they have a lifespan that lasts as long as the script that is running and whose values are accessible to all functions, whereas local variables, like the stack frame they reside in, live temporarily, only as long as the functions they are defined in are currently active. When a function call is made, its local variables come into scope as they are declared. At that time, a new local name is created for that object, and once that function has completed and the frame deallocated, that variable will go out of scope.

global_str = 'foo'
def foo():
    local_str = 'bar'
    return global_str + local_str

In the above example, global_str is a global variable while local_str is a local variable. The foo() function has access to both global and local variables while the main block of code has access only to global variables.

CORE NOTE: Searching for identifiers (a.k.a. variables, names, etc.)

When searching for an identifier, Python searches the local scope first. If the name is not found within the local scope, then an identifier must be found in the global scope or else a NameError exception is raised.

A variable's scope is related to the namespace in which it resides. We will cover namespaces formally in the next chapter; it suffices to say for now that namespaces are just naming domains which maps names to objects, a virtual set of what variable names are currently in use, if you will. The concept of scope relates to the namespace search order that is used to find a variable. All names in the local namespace are within the local scope when a function is executing. That is the first namespace searched when looking for a variable. If it is not found there, then perhaps a globally-scoped variable with that name can be found. These variables are stored (and searched) in the global and built-in namespaces.

It is possible to “hide” or override a global variable just by creating a local one. Recall that the local namespace is searched first, being in its local scope. If the name is found, the search does not continue to search for a globally-scoped variable, hence overriding any matching name in either the global or built-in namespaces.


Also, be careful when using local variables with the same names as global variables. If you use such names in a function (to access the global value) before you assign the local value, you will get an exception (NameError or UnboundLocalError), depending on which version of Python you are using.

11.8.2. global Statement

Global variable names can be overridden by local variables if they are declared within the function. Here is another example, similar to the first, but the global and local nature of the variable is not as clear.

							def foo():
    print "
calling foo()…"
    bar = 200
    print "in foo(), bar is", bar
bar = 100
print "in __main__, bar is", bar
foo()
print "
in __main__, bar is (still)", bar

It gave the following output:

in __main__, bar is 100
calling foo()…
in foo(), bar is 200
in __main__, bar is (still) 100

Our local bar pushed the global bar out of the local scope. To specifically reference a named global variable, one must use the global statement. The syntax for global is:

							global
							var1[, var2[, … varN]]]

Modifying the example above, we can update our code so that we use the global version of is_this_global rather than create a new local variable.

>>> is_this_global = "xyz"
>>> def foo():
…      global is_this_global
…      this_is_local = 'abc'
…      is_this_global = 'def'
…      print this_is_local + is_this_global
…
>>> foo()
abcdef
>>> print is_this_global
def

11.8.3. Number of Scopes

Python syntactically supports multiple levels of functional nesting; however, a maximum of two scopes is imposed: a function's local scope and the global scope. Even as more levels of functional nesting exist, you are not able to access more than two scopes.

							def foo():
    m = 3
    def bar():
        n = 4
        print m + n
    print m
    bar()

>>> foo()
Traceback (innermost last):
 File "<interactive input>", line 0, in ?
 File "<interactive input>", line 7, in foo
 File "<interactive input>", line 5, in bar
NameError: m

The access to foo()'s local variable m within function bar() is illegal because m is declared local to foo(). The only scopes accessible from bar() are bar()'s local scope and the global scope. foo()'s local scope is not included in that short list of two. Note that the output for the “print m” statement succeeded, and it is the function call to bar() that fails. (Note: this may change for future versions of Python.)

11.8.4. Other Scope Characteristics

Scope and lambda

Python's lambda expressions follow the same scoping rules as standard functions. A lambda expression defines a new scope, just like a function definition, so the scope is inaccessible to any other part of the program except for that local lambda/function.

Those lambda expressions declared local to a function are accessible only within that function; however, the expression in the lambda statement has the same scope access as the function. In other words, they have access to global variables, but neither has access to each other's local scopes. You can also think of a function and a lambda expression as siblings.

>>> x = 10
>>> def foo():
…       y = 5
…       bar = lambda :x+y
…       print bar()
…       y = 8
…       print bar()
…
>>> foo()
Traceback (innermost last):
 File "<interactive input>", line 0, in ?
 File "<interactive input>", line 4, in foo
 File "<interactive input>", line 3, in <lambda>
NameError: y

In the example above, although the lambda expression was created in the local scope of foo(), it has access to only two scopes: its local scope and the global scope (also see Section 11.8.3). We can correct it by placing a local variable z within the lambda expression that references the function local variable y.

>>> x = 10
>>> def foo():
…       y = 5
…       bar = lambda z:x+z
…       print bar(y)
…
…       y = 8
…       print bar(y)
…
>>> foo()
15
18

Variable Scope and Namespaces

From our study in this chapter, we can see that at any given time, there are either one or two active scopes—no more, no less. Either we are at the top-level of a module where we have access only to the global scope, or we are executing in a function where we have access to its local scope as well as the global scope. How do namespaces relate to scope?

From the Core Note in Section 11.8.1, we can also see that at any given time, there are either two or three active namespaces. From within a function, the local scope encompasses the local namespace, the first place a name is searched for. If the name exists here, then checking the global scope (global and built-in namespaces) is skipped. From the global scope (outside of any function), a name lookup begins with the global namespace. If no match is found, the search proceeds to the built-in namespace.

We will now present a script with mixed scope everywhere, Example 11.8. We leave it as an exercise to the reader to determine the output of the program.

Listing 11.8. Variable Scope (scope.py)

Local variables hide global variables, as indicated in this variable scope program. What is the output of this program? (And why?)

1   #!/usr/bin/env python
2   j, k = 1, 2
3
4   def proc1():
5
6       j, k = 3, 4
7       print "j == %d and k == %d" % (j, k)
8       k = 5
9
10  def proc2():
11
12      j = 6
13      proc1()
14      print "j == %d and k == %d" % (j, k)
15
16
17  k = 7
18  proc1()
19  print "j == %d and k == %d" % (j, k)
20
21  j = 8
22  proc2()
23  print "j == %d and k == %d" % (j, k)

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset