Saturday, December 24, 2011

Computational economics lecture 27


Name Resolution

Time for the details

Global and Local Namespaces

These are commonly used terms
Let's try to understand the definitions

Global Namespaces

The global namespace is the namespace of the module currently being executed
To list this namespace, use globals()
For example, suppose that we start the interpreter and begin making assignments
>>> x = 3
>>> dir()
['__builtins__', '__doc__', '__name__', 'x']
We are now working in the module __main__
Hence the namespace for __main__ is now the global namespace
Next, we import a module called amodule
>>> import amodule
The interpreter
  • Creates a namespace for the module
  • Starts executing commands in the module
The namespace amodule.__dict__ is now the global namespace
Once execution of the module finishes, interpreter returns to the module from where the import statement was made
  • In this case it's __main__
Now the namespace of __main__ is the global namespace

Local Namespaces

Suppose that inside a module we have access to a function f
def f(x):
    a = 2
    return a * x
Now we call the function
y = f(1)
The interpreter creates a local namespace for the function, and registers the variables in that namespace
Variables in the namespace are called local variables
After the function returns, the namespace is deallocated (lost)
We can view the contents of the local namespace with locals()
def f(x):
    a = 2
    print locals()
    return a * x
Now we call the function
y = f(1)
{'a': 2, 'x': 1}

The __builtins__ Namespace

We have been using some built-in objects (mainly functions)
  • max(), dir(), str(), list(), len(), range(), type(), etc.
How does access to these names work?
  • These definitions are stored in a module called __builtin__
  • They have there own namespace, called __builtins__
>>> dir()  
['__builtins__', '__doc__', '__name__']
>>> dir(__builtins__)
[... 'iter', 'len', 'license', 'list', 'locals', ...] 
We can access elements of the namespace as follows
>>> __builtins__.max
<built-in function max>
But __builtins__ is special, because we can access them directly as well:
>>> max
<built-in function max>
>>> __builtins__.max == max
True
The reason why this works is explained in the next section...

Name resolution

When we reference a name, how does the Python interpreter find the corresponding value?

The Process of Name Resolution

At any point of execution, there are two or three namespaces which can be accessed directly
  • Directly means without using a dot
    • pi rather than math.pi
If the interpreter is not executing a function call then the namespaces are
  • The global namespace (of the module being executed)
  • The builtin namespace
Suppose that we refer to a name
print x
The interpreter
  • First looks in the global namespace for x
  • If it's not there, looks in the builtin namespace
  • If it's not there, raises a NameError
If the interpreter is executing a function call
y = f(1)
Then the namespaces are
  • The local namespace of f
  • The global namespace (of the module being executed)
  • The builtin namespace
Now the interpreter
  • First looks in the local namespace
  • Then in the global namespace
  • Then in the builtin namespace
  • If it's not there, raises a NameError

Consequences

Consider the script test.py
def g(x):
    a = 1
    x = x + a
    return x

a = 0
y = g(10)
print "a = ", a, "y = ", y
What happens when I run this script?
$ python -i test.py
a = 0 , y = 11
>>> x
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
  • The global namespace {} is created
  • The function object is created, g is bound to it
    • g stored in the global namespace
  • Next, the global variable a is created, bound to 0
    • a stored in the global namespace
  • Next g is called via y = g(10)
    • Local namespace {} is constructed
    • Local x and a are added to it
      • Local namespace = {'x': 10, 'a': 1}
      • x = x + a uses the local a
      • Local a does not interfere with global a
  • After computations, return value assigned to y
  • Local x and a are discarded (namespace is deallocated)
Note that global a was not affected by local a


Mutable Versus Immutable Parameters

Consider the following code segment
def f(x):
    x = x + 1
    return x
x = 1
print f(x), x 
Prints 2 as the value of f(x) and 1 as the value of x
  • f is registered as a function in the global namespace
  • x bound to 1 in the global namespace
  • Call f(x)
    • Creates a local namespace
    • Adds x to local namespace, bound to 1
    • Rebinds this local x to the new integer object 2
      • The value 1 is now garbage collected
    • Returns the value of local x
    • Local namespace deallocated, local x lost
  • Prints the return value 2 for f(x), and the value 1 for global x
Different story when we use a mutable data type such as a list:
def f(x):
    x[0] = x[0] + 1
    return x
x = [1]
print f(x), x 
Prints [2] as the value of f(x) and same for x
  • f is registered as a function in the global namespace
  • x bound to [1] in the global namespace
  • Call f(x)
    • Creates a local namespace
    • Adds x to local namespace, bound to [1]
    • The list [1] is modified to [2]
    • Returns the list [2]
    • Local namespace deallocated, local x lost
  • Global x has been modified
Conclusion: functions can modify global variables if they are mutable

0 comments: