---
# System prepended metadata

title: CS 1358 Introduction to Programming in Python SC9
tags: [pythonSC]

---

# CS 1358 Introduction to Programming in Python SC9

###### tags: `pythonSC`

Answer the following questions to check your understanding of your material.  Expect the same kind of questions to show up on your tests.  

# 1. Definitions and Short Answers - functions
1. What is the equivalent lambda expression that computes the same as the following named function?
    ```python
    def Double(n):
        return n + n

    lambda n: n + n

    def Bigger(a, b):
        return a if a > b else b

    lambda a, b: a if a >ｂ else b
    ```

2. What lambda expression can you pass to a list's sort method's optional key plug-in function if you want to sort a list of strings by string length?  For example
    ```shell
    >>> L = ['an', 'apple', 'a', 'day', 'keeps', 'the', 'doctor', 'away']
    >>> L.sort(key=lambda     )
    >>> L
    ['a', 'an', 'day', 'the', 'away', 'apple', 'keeps', 'doctor']
    ```

    ```python
    L.sort(key = lambda s: len(s))
    ```

3. If you want to sort a list of strings primarily by length and secondarily alphabetically (case-sensitive), what lambda would you pass to the key parameter of the list's sort method?  Fill in the yellow blank below.
    ```shell
    >>> L = ['a', 'glass', 'of', 'water', 'is', 'empty', 'or', 'full']
    >>> L.sort(key=lambda     )
    >>> L
    ['a', 'is', 'of', 'or', 'full', 'empty', 'glass', 'water']
    ```
    ```python
    L.sort(key = lambda s:(len(s), s))
    ```

4. Which of the following can properly sort a list of month names by month order, and why or why not?  Assuming the following global symbols have been defined.
    ```python
    ML = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
    MD = {'Jan':1, 'Feb':2, 'Mar':3, 'Apr':4, 'May':5, 'Jun':6, 'Jul':7, 'Aug':8, 'Sep':9, 'Oct':10, 'Nov':11, 'Dec':12}
    L = [ 'Apr', 'May', 'Nov', 'Mar', 'Jan', 'Feb', 'Oct','Jun', 'Jul', 'Aug', 'Sep', 'Dec']

    L.sort(key=ML) #TypeError: 'list' object is not callable
    L.sort(key=MD) #TypeError: 'dict' object is not callable
    L.sort(key=lambda x: ML[x]) #TypeError: list indices must be integers or slices, not str
    L.sort(key=lambda x: MD[x])
    L.sort(key=lambda x: ML.index(x))
    L.sort(key=lambda x: MD.index(x)) #AttributeError: 'dict' object has no attribute 'index'
    ```

5. If chr(97) evaluates to 'a', then what is the value of
    ```python
    list(map(chr, [97, 98, 99, 100, 101]))
    ['a', 'b', 'c', 'd', 'e']
    ```


6. What is the value of
    ```python
    list(map(max, [1, 7, 2, 8], [5, 6, 3, 0]))
    [5, 7, 3, 8]
    ```


7. How do you use the built-in function zip to convert lists [1, 7, 2, 8] and [5, 6, 3, 0] into a list of tuples, as in [(1, 5), (7, 6), (2, 3), (8, 0)]
    ```python
    list(zip([1, 7, 2, 8], [5, 6, 3, 0]))
    ```


8. How to you write the equivalent list-comprehension version of 
    ```python
    list(map(max, [1, 7, 2, 8], [5, 6, 3, 0]))

    list(max(i) for i in zip([1, 7, 2, 8], [5, 6, 3, 0]))
    ```


9. Suppose you want to do
    ```python
    list(map(lambda x, y: x+y, [1, 7, 2, 8], [5, 6, 3, 0]))
    ```
    but replace the lambda expression (underlined above) with an existing function that does the same.  What can you use instead?
    (Hint: import from the operator module)

      ```python
    from operator import add
    list(map(add (x ,y), [1, 7, 2, 8], [5, 6, 3, 0]))
      ```


10. If you want to read and print lines from a file but skip all blank lines using the following code template
    ```python
    fh = open('myfile')
    for line in filter(lambda a : a!='\n', fh.readlines()):
        print(line, end='') # no need to print extra newline
    fh.close()
    ```
    What should you put as the lambda expression above?  Note that a blank line consists of a single newline character.


11. In the stack interpreter example, several versions of the interpreter are given.
    The if-elif version looks like this:

    ```python
     1  def StackInterpreter():
     2      L = []
     3      while True:
     4          line = input('command? ')
     5          words = line.split()
     6          if len(words) == 0:
     7              pass
     8          elif words[0] == 'show':
     9              print(L)
    10          elif words[0] == 'push':
    11              L.extend(words[1:])
    19          elif words[0] == 'pop':
    20              print(L.pop())
    21          elif words[0] == 'quit':
    22              break
    23          else:
    24              print('unknown command')
    ```
    How can lines 8-24 be replaced with a check for quit followed by using the command word (i.e., words[0]) to look up and execute the corresponding action?  That is,
    ```python
     8         if words[0] == 'quit':
     9             break
    10         D = {'show': lambda : print(L),
    11          'push': lambda : L.extend(words[1:]),
    12          'pop':  lambda : print(L.pop()),
    13         }
    14         f = D.get(words[0], lambda : print('unknown command'))
    15         f()
    ```
    a. on line 10' (i.e., revised line 10), what should go into the blank?  Will it work if you fill in the blank on line 10' with print(L)? Why or why not?  
     > No, because 'print(L)' is not a callable object

    b. on line 11', what should go into the blank? 

    c. on line 12', what should go into the blank?

    d. what does the D.get(key, altval) method do?  How would it be rewritten without calling the .get() method?
    what goes into the blank on line 14'?
     > D.get(key, altval) will return D['key'] if key existed in D, else return altval

    e. can lines 10'-15' be rewritten without using temporary variables D and f?  How?
     > It must have D but it can don't use F by add '()' after the D.get(), so that D.get() will call the function automatically.


12. One alternative to lambda in the lookup table above is to use inner functions, 
    ```python
     1  def StackInterpreter():
     2      L = []
     3      def show(): # inner function
     4          print(L)
     5      def push():
     6          L.extend(words[1:])
     7      def pop():
     8          print(L.pop())
     9      def unknown():
    10          print('unknown command')
    11      D = {'show': show, 'push': push, 'pop':  pop }
    12      while True:
    13          line = input('command? ')
    14          D.get(words[0], unknown)()
    ```

    a. What are the inner functions in this code fragment?
     > show, push, pop, unknown

    b. Why would it be preferable to using inner functions in this case (hint: line 11)?
     > named, instead of exposing detail like lambda

    c. How would the lookup code D.get(words[0], ______)be written differently from the lambda version?  Fill in the blank.

13. How can you add the documentation string (docstring) to the StackInterpreter() function above so that you can do help(StackInterpreter) in interactive mode and get the help text?
    ```shell
    $ python3 -i stack.py
    >>> help(StackInterpreter)
        This is a stack interpreter. The commands are:
        show                   -- shows stack content
        push item1 item2 item3 -- pushes item1,... as str on stack
        pop                    -- pops and displays popped data
        quit                   -- exit interpreter
    END
    >>>
    ```
    > write a triple-quoted string immediately after def line


14. Does Python Style Guide recommend using camel case or snake case for function names?
     > snake_case  

15. What are examples of recursive data types in Python?  Are the following data types recursive?
    - [ ]     int
    - [x]     list
    - [x]     tuple
    - [x]     dict
    - [ ]     set
    - [ ]     float
    - [ ]     bool
16. What is a recursive function?
     > a function that calls itself directly or indirectly

17. What is a base case in a recursive function?  Should all recursive functions have at least one base case?  Why or why not?
     > base case : return without function call
     > without base case : function might never return

18. If you want to count the number of integers in a list that may contain either integers or list of integers and other lists (of integers and other lists…), 
    ```
    a. Can you use a loop such as follows?  If not, for what cases will it fail?
    ```
    ```python=
     def count_ints(L):
        n = 0
        for i in L:
            if type(i) == int:
                n += 1
        return n
    ```
    > No, it didn't recursively call, when the element in L is a list, it may fail.
    ```
    b. Can you use a loop such as follows?  If not, for what cases will it fail?
    ```
    ```python=
    def count_ints(L):
        n = 0
        for i in L:
            if type(i) == int:
                n += 1
            elif type(i) == list:
                for j in i:
                    n += 1
        return n
    ```
    > No, it didn't recursively call, when the element in L is a list and it's element has a list, it may fail. 
    ```
    c. Fill in the code below for counting recursively. You may assume types of elements are either int or list.  Note that this version of the code is slightly differently from the slide.
    ```
    ```python=
    def count_ints(L):
        if type(L) == int:  # base case
            return 1
        else:
            n = 0
            for i in L:
                n += count_ints(i)
            return n
    ```

19. Recursion can also replace a loop.  Rewrite the count_int by converting the loop into a recursive call with its own base case (i.e., loop's terminating condition) and another recursive case for "the rest of the loop".
    ```python
     1  def rec_count(L):
     2      if type(L) == int:  # first base case
     3          return 1
     4      if len(L) == 0 :  # 2nd base (L is list) so, what kind of list?
     5          return 0
     6      return rec_count(L[0]) + rec_count(L[1:])
     7          # one recursive call for current element, and 
     8          # 2nd recursive call for "the rest of the loop"
    ```

20. Explain what the following functions do in terms of what the parameters are (if any) and what the return value is.
    os.getcwd()
    > get current working directory path (string)

    os.listdir(d)
    > get list of names of files and directories in directory d

    os.path.isdir(d)
    > check if d (string) is a directory

21. To count files recursively, consider the following version of code
    ```python
     1  def count_files(p = '.'):
     2      import os
     3      if not os.path.isdir(p): # p is the name of a file, not a directory
     4          return 1
     5      dir_content = os.listdir(p) # get list of names (files & dir)
     6      return sum(map(count_files, dir_content)) # sum recursive count of content
    ```
    a. What does '.' mean as the default value of parameter p? 
    > current directory

    b. How do you call a function from os module to check if a path p is a file rather than a directory ("folder")?  Fill in the blank on line 3.

    c. If p a path is a directory, how do you obtain a list of names (of files and directories) in p?  Fill in the blank on line 5.

    d. How do you recursively count each path of the list so that the counts can be summed?  Fill in the blank on line 6.


22. In the recursive-find example,
    ```python
    def rec_find(L, val):
        if type(L) in {list, tuple}: # if look inside members of L
            for i, v in enumerate(L):
                p = rec_find(v, val) # recursively find each member
                if p == True: # L[i] == val, so we return (i,)
                    return (i,)
                if p != False: # L[i] recursively found val,
                    return (i,)+p # so we prepend i to its path p
        return L == val # either L is not seq or for-loop didn't find
    ```
    a. calling
    ```python
    M = [1, 2, [3, [4, 23]
    rec_find(M, 23)
    ```
    results in the tuple value (2, 1, 1).  What does it mean?
    > the value 23 is at M[2][1][1]

    b. Calling
    ```python
    rec_find(43, 43)
    ```
    results in True.  What does it mean?
     > 43 == 43

    c. What would be the result of calling?
    ```python
    rec_find([1, 2, 3], [1, 2, 3])
    
    True
    ```
    
    d. What would be the result of calling?
    ```python
    rec_find([[1, 2, 3]], [1, 2, 3])
    
    (0,)
    ```

22. The source code for the recursive-find function is same at 24:
    
    a. What is the condition of the base case in this recursive function?
     > if L is not list or tuple

    b. Is line 9 executed only if type(L) is not in {list, tuple}?  Or can it be executed even if type(L) is either list or tuple?  If so, describe how line 9 can still be reached after executing lines 3-8?
     > Not only, it has no condition. 
    
    c. Can line 9 compare only two ints, or can it be comparing two tuples or two lists?
     > it can compare anything

    d. Line 5 tests
        5              if p == True:
        but why can't it be replaced with
        5              if p:
    > because it may return not only boolean may return tuple

    e. Line 7 tests
        7              if p != False:
        but why isn't it redundant with line 5?  Doesn't 
        p != False 
        imply
        p == True
     > same reason as last question

24. In the code for indenting list items by their level of nesting, 
    ```python
     1  def indent_list(L, level=0):
     2      if L == None:
     3          return
     4      if type(L) in {list, tuple}:
     5          for child in L:
     6              indent_list(child, level+1)
     7      else:
     8          print(f'{" "*4*level}{L}')
     9  if __name__ == '__main__':
    10      L = ['F1', ['F4', 'F5', ['F8']], 'F2', 'F3', \
    11          'D3', ['F6', 'F7']]
    12      indent_list(L)
    ```
    a. By the time 'F8' is printed in the test case, how many copies of indent_list calls are active?  What are the values of the parameters L and level?
     > 7,  L = 'F8', level = 2
    
    b. Is line 2 ever executed when running the test case?
     > Yes, thete is no empty list
     > 
    c. How many times total is indent_list(L) called in the test case above?  How can you modify the code above to print your answer?
     > 13, set a global or static variable in the function increament every time .


