Sunday, 23 March 2014

Week10 - Scope and Namespace


Hi Everyone!

In this week's lecture, Danny still kept talking of A2 implementation. We only learned a new Quick sort, I guess there will be more sorting stuff in the following weeks. So I will just skip it right now, and talk about something that we've missed in the past. 

In Week 5, we learned about Namespace & Space but I didn't talk about since it was only mentioned a few minutes in lecture. Even though this topic is not important for this course, and it takes me a long time to search for other materials to understand it; but I still want to post it here. I feel it really helps me understand more deeply about how each function works. Hope you will benefit from this as well~


Scope and Namespace

Sometimes, computer programming computations are very complex, and we want to break them down into separate steps to create a clearer code. For an example, we want to write function to evaluate the quadratic polynomial ax^2 + bx + c into several steps. (*this example comes from the book Practical Programming, Paul Gries, Jennifer Campbell, Jason Montojo)


1. Scope

def quadratic(a, b, c, x):
    first = a * x ** 2
    second = b * x
    third = c
    return first + second + third
>>> quadratic(2, 3, 4, 0.5)
6.0

Variables that are created with a function are called local variables(first, second, third in this case). Local variables get created each time that function is called, and they are erased when the function returns; therefore, they cannot be used outside the function.



>>>first
Traceback (most recent call last):
  File "<string>", line 1, in <fragment>
builtins.NameError: name 'first' is not defined

The area of a program that a variable can be used in it is called the variable's scope. For example, the scope of a local variable is from the line in which it is defined up to the end of the function. In this case, the scope for local variable first is from "first = ..." to "return..."


2. Namespace

Namespace is a space for names, which stores local variables for a function call. It is a mapping from names to objects. Whenever Python executes a function call, it creates a namespace for this function call exactly.


def f(x):
    x = 2 * x
    return x
>>>x = 1
>>>x = f(x+1) + f(x+2)
It seems confusing, but each function call f(...) has its own namespace. This namespace contains the function's own x, which means the x in every different namespace has different memory address and contains different values. That's how the function works correctly because of different namespaces.

Frames
Global variables
f
id1
x
id2
f
x
id4
Return
value
id4
Objects
id1:function
f(x)
id2:int
1
id4:int
4


3. Python Searching Order

I was confused with why the following twin-look functions produced different results. In CSC108, Michelle told us it is because in the second function the original list L has also been modified. But I was not actually convinced at that time. Now we can explain it by Python Searching Order:
1. Innermost scope, local variables
2. Enclosing scopes, nonlocal variables
3. Global scope, global variables
4. Built-in names
*The global scope is the scope contains the  current module's global name or __main__ 
*The nonlocal scope is the scope of any enclosing functions
*The outmost scope is the corresponding namespace containing built-in names. 

def H(l):
    for x in l:
        x = x ** 2
    return l
>>>l = [1,2,3]
>>>H(l)
[1, 2, 3]
*When H(l) is called, Python looks into "for x in l" local scope first, there is x in local scope, so Python stops looking for x and operates the command for x in a local scope level. Therefore, l has not been modified. The local scope operation has no effect to nonlocal variable. H(l) returns the nonlocal l and it does not change.

def I(l):
    for i in range(len(l)):
        l[i] = l[i] ** 2
    return l
>>>l = [1,2,3]
>>>I(l)
[1, 4, 9]
* When I(l) is called, Python looks into "for i in range(len(l))" local scope first, there is no l in local scope. Then Python starts to search for l in nonlocal scope, there is l in nonlocal scope "I(l)". Therefore Python operates the command for l[i] with a nonlocal scope level l, each time the nonlocal scope l has been modified. H(l) returns the nonlocal l, which has been modified.

In addition, we can rebind variables to different scopes by using global, nonlocal or local statement as needed.  
sample code: global spam (*spam is a variable here)


That's basically what I know so far, please share with any comment and let's work on this together.
See you then!

4 comments:

  1. Sometimes I get confused with local names and global names when I writing code. Thank you for your sharing

    ReplyDelete
  2. just be really careful about the namespace. the global name can be used before creating. The nonlocal and local can not, there will be an error. And when using nonlocal, the order of searching is from inside to outside without the inner most and the outer most.

    ReplyDelete
    Replies
    1. hey, thank you for your comment!
      what do you mean by "without the inner most and the outer most"? I am confused. Could you please explain more?

      Delete