10.15 Namespaces and Scopes

  • Each identifier has a scope that determines where you can use it in your program, and we introduced the local and global scopes
  • Scopes are determined by namespaces, which associate identifiers with objects and are implemented “under the hood” as dictionaries
  • Namespaces are independent of one another
    • Same identifier may appear in multiple namespaces
  • Three primary namespaces—local, global and built-in.

Local Namespace

  • Each function and method has a local namespace that associates local identifiers (parameters and local variables) with objects
  • 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

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.

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
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
  • 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
      • 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 as print’s argument
      • To call the function, Python must find print’s corresponding object
      • Python looks in the local namespace, which does not define print
      • Next, Python looks in the session’s global namespace, which does not define print
      • Finally, Python looks in the built-in namespace, which does define print
      • 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
      • 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 as print’s argument
  • 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
In [4]:
y
------------------------------------------------------------------------
NameError                              Traceback (most recent call last)
<ipython-input-4-9063a9f0e032> in <module>
----> 1 y

NameError: name 'y' is not defined
  • 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
  • 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
In [5]:
z
Out[5]:
'global z'

Nested Functions

  • There is also an enclosing namespace
  • Python allows you to define nested functions inside other functions or methods
  • 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

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

©1992–2020 by Pearson Education, Inc. All Rights Reserved. This content is based on Chapter 5 of the book Intro to Python for Computer Science and Data Science: Learning to Program with AI, Big Data and the Cloud.

DISCLAIMER: The authors and publisher of this book have used their best efforts in preparing the book. These efforts include the development, research, and testing of the theories and programs to determine their effectiveness. The authors and publisher make no warranty of any kind, expressed or implied, with regard to these programs or to the documentation contained in these books. The authors and publisher shall not be liable in any event for incidental or consequential damages in connection with, or arising out of, the furnishing, performance, or use of these programs.