DekGenius.com
[ Team LiB ] Previous Section Next Section

14.9 Part IV Exercises

We're going to start coding more sophisticated programs in these exercises. Be sure to check solutions in Section B.4, and be sure to start writing your code in module files. You won't want to retype these exercises from scratch if you make a mistake.

  1. The basics. At the Python interactive prompt, write a function that prints its single argument to the screen and call it interactively, passing a variety of object types: string, integer, list, dictionary. Then try calling it without passing any argument. What happens? What happens when you pass two arguments?

  2. Arguments. Write a function called adder in a Python module file. The function adder should accept two arguments and return the sum (or concatenation) of its two arguments. Then add code at the bottom of the file to call the function with a variety of object types (two strings, two lists, two floating points), and run this file as a script from the system command line. Do you have to print the call statement results to see results on your screen?

  3. varargs. Generalize the adder function you wrote in the last exercise to compute the sum of an arbitrary number of arguments, and change the calls to pass more or less than two. What type is the return value sum? (Hints: a slice such as S[:0] returns an empty sequence of the same type as S, and the type built-in function can test types; but see the min examples in Chapter 13 for a simpler approach.) What happens if you pass in arguments of different types? What about passing in dictionaries?

  4. Keywords. Change the adder function from Exercise 2 to accept and add three arguments: def adder(good, bad, ugly). Now, provide default values for each argument and experiment with calling the function interactively. Try passing one, two, three, and four arguments. Then, try passing keyword arguments. Does the call adder(ugly=1, good=2) work? Why? Finally, generalize the new adder to accept and add an arbitrary number of keyword arguments, much like Exercise 3, but you'll need to iterate over a dictionary, not a tuple. (Hint: the dict.keys( ) method returns a list you can step through with a for or while.)

  5. Write a function called copyDict(dict) that copies its dictionary argument. It should return a new dictionary with all the items in its argument. Use the dictionary keys method to iterate (or, in Python 2.2, step over a dictionary's keys without calling keys). Copying sequences is easy (X[:] makes a top-level copy); does this work for dictionaries too?

  6. Write a function called addDict(dict1, dict2) that computes the union of two dictionaries. It should return a new dictionary, with all the items in both its arguments (assumed to be dictionaries). If the same key appears in both arguments, feel free to pick a value from either. Test your function by writing it in a file and running the file as a script. What happens if you pass lists instead of dictionaries? How could you generalize your function to handle this case too? (Hint: see the type built-in function used earlier.) Does the order of arguments passed matter?

  7. More argument matching examples. First, define the following six functions (either interactively, or in a module file that can be imported):

    def f1(a, b): print a, b             # Normal args
    
    def f2(a, *b): print a, b            # Positional varargs
    
    def f3(a, **b): print a, b           # Keyword varargs
    
    def f4(a, *b, **c): print a, b, c    # Mixed modes
    
    def f5(a, b=2, c=3): print a, b, c   # Defaults
    
    def f6(a, b=2, *c): print a, b, c    # Defaults and positional varargs

    Now, test the following calls interactively and try to explain each result; in some cases, you'll probably need to fall back on the matching algorithm shown in Chapter 13. Do you think mixing matching modes is a good idea in general? Can you think of cases where it would be useful?

    >>> f1(1, 2)                  
    >>> f1(b=2, a=1)              
    
    >>> f2(1, 2, 3)               
    >>> f3(1, x=2, y=3)           
    >>> f4(1, 2, 3, x=2, y=3)     
    
    >>> f5(1)                    
    >>> f5(1, 4)                 
    
    >>> f6(1)                    
    >>> f6(1, 3, 4)
  8. Primes revisited. Recall the code snippet we saw in Chapter 10, which simplistically determines if a positive integer is prime:

    x = y / 2                          # For some y > 1
    while x > 1:
        if y % x == 0:                 # Remainder
            print y, 'has factor', x
            break                      # Skip else
        x = x-1
    else:                              # Normal exit
        print y, 'is prime'

    Package this code as a reusable function in a module file, and add some calls to your function at the bottom of your file. While you're at it, replace the first line's / operator with //, to make it handle floating point numbers too, and be immune to the "true" division change planned for the / operator in Python 3.0 as described in Chapter 4. What can you do about negatives and 0 and 1? How about speeding this up? Your outputs should look something like this:

    13 is prime
    13.0 is prime
    15 has factor 5
    15.0 has factor 5.0
  9. List comprehensions. Write code to build a new list containing the square roots of all the numbers in this list: [2, 4, 9, 16, 25]. Code this as a for loop first, then as a map call, and finally as a list comprehension. Use the sqrt function in the built-in math module to do the calculation (i.e., import math, and say math.sqrt(x)). Of the three, which approach do you like best?

    [ Team LiB ] Previous Section Next Section