10.15 Namespaces and Scopes

In the “Functions” chapter, we showed that each identifier has a scope that determines where you can use it in your program, and we introduced the local and global scopes. Here we continue our discussion of scopes with an introduction to namespaces.

Scopes are determined by namespaces, which associate identifiers with objects and are implemented “under the hood” as dictionaries. All namespaces are independent of one another. So, the same identifier may appear in multiple namespaces. There are three primary namespaces—local, global and built-in.

Local Namespace

Each function and method has a local namespace that associates local identifiers (such as, parameters and local variables) with objects. The local namespace exists from the moment the function or method is called until it terminates and is accessible only to that function or method. In a function’s or method’s suite, assigning to a variable that does not exist creates a local variable and adds it to the local namespace. Identifiers in the local namespace are in scope from the point at which you define them until the function or method terminates.

Global Namespace

Each module has a global namespace that associates a module’s global identifiers (such as global variables, function names and class names) with objects. Python creates a module’s global namespace when it loads the module. A module’s global namespace exists and its identifiers are in scope to the code within that module until the program (or interactive session) terminates. An IPython session has its own global namespace for all the identifiers you create in that session.

Each module’s global namespace also has an identifier called __name__ containing the module’s name, such as 'math' for the math module or 'random' for the random module. As you saw in the previous section’s doctest example, __name__ contains '__main__' for a .py file that you run as a script.

Built-In Namespace

The built-in namespace contains associates identifiers for Python’s built-in functions (such as, input and range) and types (such as, int, float and str) with objects that define those functions and types. Python creates the built-in namespace when the interpreter starts executing. The built-in namespace’s identifiers remain in scope for all code until the program (or interactive session) terminates.20

Finding Identifiers in Namespaces

When you use an identifier, Python searches for that identifier in the currently accessible namespaces, proceeding from local to global to built-in. To help you understand the namespace search order, consider the following IPython session:

In [1]: z = 'global z'

In [2]: def print_variables():
   ...:     y = 'local y in print_variables'
   ...:     print(y)
   ...:     print(z)
   ...:
In [3]: print_variables()
local y in print_variables
global z

The identifiers you define in an IPython session are placed in the session’s global namespace. When snippet [3] calls print_variables, Python searches the local, global and built-in namespaces as follows:

  • Snippet [3] is not in a function or method, so the session’s global namespace and the built-in namespace are currently accessible. Python first searches the session’s global namespace, which contains print_variables. So print_variables is in scope and Python uses the corresponding object to call print_variables.

  • As print_variables begins executing, Python creates the function’s local namespace. When function print_variables defines the local variable y, Python adds y to the function’s local namespace. The variable y is now in scope until the function finishes executing.

  • Next, print_variables calls the built-in function print, passing y as the argument. To execute this call, Python must resolve the identifiers y and print. The identifier y is defined in the local namespace, so it’s in scope and Python will use the corresponding object (the string 'local y in print_variables') as print’s argument. To call the function, Python must find print’s corresponding object. First, it looks in the local namespace, which does not define print. Next, it looks in the session’s global namespace, which does not define print. Finally, it looks in the built-in namespace, which does define print. So, print is in scope and Python uses the corresponding object to call print.

  • Next, print_variables calls the built-in function print again with the argument z, which is not defined in the local namespace. So, Python looks in the global namespace. The argument z is defined in the global namespace, so z is in scope and Python will use the corresponding object (the string 'global z') as print’s argument. Again, Python finds the identifier print in the built-in namespace and uses the corresponding object to call print.

  • At this point, we reach the end of the print_variables function’s suite, so the function terminates and its local namespace no longer exists, meaning the local variable y is now undefined.

To prove that y is undefined, let’s try to display y:

In [4]: y
-------------------------------------------------------------------------
NameError                               Traceback (most recent call last)
<ipython-input-4-9063a9f0e032> in <module>()
----> 1 y

NameError: name 'y' is not defined

In this case, there’s no local namespace, so Python searches for y in the session’s global namespace. The identifier y is not defined there, so Python searches for y in the built-in namespace. Again, Python does not find y. There are no more namespaces to search, so Python raises a NameError, indicating that y is not defined.

The identifiers print_variables and z still exist in the session’s global namespace, so we can continue using them. For example, let’s evaluate z to see its value:

In [5]: z
Out[5]: 'global z'

Nested Functions

One namespace we did not cover in the preceding discussion is the enclosing namespace. Python allows you to define nested functions inside other functions or methods. For example, if a function or method performs the same task several times, you might define a nested function to avoid repeating code in the enclosing function. When you access an identifier inside a nested function, Python searches the nested function’s local namespace first, then the enclosing function’s namespace, then the global namespace and finally the built-in namespace. This is sometimes referred to as the LEGB (local, enclosing, global, built-in) rule. In an exercise, we ask you to create a nested function to demonstrate this namespace search order.

Class Namespace

A class has a namespace in which its class attributes are stored. When you access a class attribute, Python looks for that attribute first in the class’s namespace, then in the base class’s namespace, and so on, until either it finds the attribute or it reaches class object. If the attribute is not found, a NameError occurs.

Object Namespace

Each object has its own namespace containing the object’s methods and data attributes. The class’s __init__ method starts with an empty object (self) and adds each attribute to the object’s namespace. Once you define an attribute in an object’s namespace, clients using the object may access the attribute’s value.

tick mark Self Check

  1. (Fill-In) A function’s _________ namespace stores information about identifiers created in the function, such as its parameters and local variables.
    Answer: local.

  2. (True/False) When a function attempts to get an attribute’s value, Python searches the local namespace, then the global namespace, then the built-in namespace until it finds the attribute; otherwise, a NameError occurs.
    Answer: True.

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

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