Monday, February 17, 2014

Week 6: Binary Tree and Usage of Some Built-in Functions

   This week, I learned something about recursive structures. Binary tree is a kind of recursive structure. Generally, it has one node, left tree and right tree. Left tree and right tree can be either none or another tree. It is where the recursive structure from. Tree-list is one way to represent a tree. And it can also be represented as a class. To traversal a tree, we have pre-order(node, left, right), in-order(left, node, right) and post-order(left, right, node). I did not know the usefulness until I went through some examples in use of tree structure in the reading material. For instance, we can use a tree expression to translate a mathematical expression like '(3 + 7)  * 9' (see the graph above). Also use a binary tree to deal with a series of recursive questions is quite benefit. We can let the node be a question. If the answer is 'yes', read the right tree and if the answer is 'no', read the left tree. And we can create another tree to create more question recursively. See how to think like a computer scientist - Tree , it is very interesting. I have scanned the handout for assignment 2. It is also about recursive structure. In my opinion, translating a regular expression to a tree representation is quite helpful when dealing with problems like matching strings.
    Another thing I get this week is some use of built-in functions. They makes code shorter and the program more efficient. See Built-in Functions .
          1. all(iterable)
    Return True if all elements of the iterable are true (or if the iterable is empty).
2. any(iterable)
    Return True if any element of the iterable is true. If the iterable is empty, return False.
3. filter(function, iterable)
    Construct an iterator from those elements of iterable for which function returns true. iterable may be either a sequence, a container which supports iteration, or an iterator. If function is None, the identity function is assumed, that is, all elements of iterable that are false are removed.
4. map(function, iterable, ...)
    Return an iterator that applies function to every item of iterable, yielding the results. If additional iterable arguments are passed, function must take that many arguments and is applied to the items from all iterables in parallel. With multiple iterables, the iterator stops when the shortest iterable is exhausted. For cases where the function inputs are already arranged into argument tuples, see itertools.starmap().
5. repr(object)
    Return a string containing a printable representation of an object.
6. zip(*iterables)
    Returns an iterator of tuples, where the i-th tuple contains the i-th element from each of the argument sequences or iterables. The iterator stops when the shortest input iterable is exhausted. With a single iterable argument, it returns an iterator of 1-tuples. With no arguments, it returns an empty iterator.
                         >>> x = [1, 2, 3]
                         >>> y = [4, 5, 6]
                         >>> zipped = zip(x, y)
                         >>> list(zipped)
                         [(1, 4), (2, 5), (3, 6)]
                         >>> x2, y2 = zip(*zip(x, y))
                         >>> x == list(x2) and y == list(y2)
                         True
 
    We wrote some equivalent code during the lab using non-built-in functions. But use of built-in functions as well as built-in modules is of great importance to program in python.
 
Reference: http://openbookproject.net/thinkcs/python/english3e/trees.html
                  http://docs.python.org/3.3/library/functions.html
 
 
 
 

Thursday, February 6, 2014

Week 5: Name Problems in Python

    At the beginning of learning to write functions, I find local variables very confusing. Through a period of study and this weeks' topic, I gained a deeper understanding about name matters. As follows I wrote down some points in order to remind myself.
    As I learned in Wednesday's lecture, every name in Python has a value and every value is a reference to an address of an object. Current module or '__main__' names are global names. It is visible to the whole module. Inside a function, the names are local names, which are only visible under the function. Outside the function, the name is not defined. But inside a function, we may use key word 'global' to define a name globally, or it is seen as local by default. In cases we define a function inside a function, we may use key word 'nonlocal' to get approach to the name in upper layers. python docs namespace example is a great help to understand them. Sometimes, names that seems to be same are totally different. Python reads local name first without 'global' 'nonlocal' or other key words. Also in Python there are some built-in names. When we write our own code, we should try to avoid using global names or built-in names. It may get messed if we use them.
    In term of names in class methods, child class sometimes overrides its super class. When we call a child class method that also appear in its super class, Python runs the method in the child class, no matter where the method call is(even inside a super class method call). Recursive functions are sometimes a little hard to trace, because in the stack frame(seen in visualizer), I find the same names appear many times and the frame repeated itself again and again. So in general, do not trace recursive functions too far.

def scope_test():
    def do_local():
        spam = "local spam"
    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"
    def do_global():
        global spam
        spam = "global spam"
    spam = "test spam"
    do_local()
    print("After local assignment:", spam)
    do_nonlocal()
    print("After nonlocal assignment:", spam)
    do_global()
    print("After global assignment:", spam)

scope_test()
print("In global scope:", spam)
# From http://docs.python.org/3.3/tutorial/classes.html#scopes-and-namespaces-example

   

Saturday, February 1, 2014

Week4: Use of Unittest

    In this week's lab, we used the Python test module  'unittest' to test the methods of the class we wrote. Accustomed to use doctest in the past, I find unittest unfamiliar. Here I will  summarize some basic use of unittest to remind myself in the future.
    To test a module, we should write in a new module and import unittest module and the the module we want to test.  To get start, we should write a subclass of unittest.TestCase or unittest.FuctionTestCase. The method setUp() runs automatically before testing each method. And likewise, the method tearDown() runs automatically after each test of cases. To test a method or a function, we write methods starting with the four lowercase 'test', so that the module would test it by itself. In each test case method, we call one of the method *.assert**(), such as *.assertEqual() to verify an expected result, *.assertTrue() to check a condition and *.assertRaises() to check an exception to raise. In particular, *.assertRaises() is what I find most uncomfortable because it is something I never use. It should be used as *.assertRaises(exception, callable, *args, **kwds). In lab time, we spend a long time to deal with the raises test. At last, we call the main() function of unittest to test all the subclasses of unittest.TestCase.
    The most important thing to test a module is the choice of test cases. Poorly designed cased may not find important bugs in a module, so it will spend more time in the future. The general consideration includes size, dichotomies, boundaries, order, etc.
    I find unittest extremely useful, because unlike doctest, it can contain more test cases. Also in doctest, it has shortcomings such as dealing with newline character '\n', which is what I found in an exercise. But this will not happen in unittest.

Reference: http://docs.python.org/3.1/library/unittest.html