I l@ve RuBoard Previous Section Next Section

C.4 Chapter 4

  1. Basics.

    % python
    >>> def func(x): print x
    ...
    >>> func("spam")
    spam
    >>> func(42)
    42
    >>> func([1, 2, 3])
    [1, 2, 3]
    >>> func({'food': 'spam'})
    {'food': 'spam'}
  2. Arguments. Here's what one solution looks like. You have to use print to see results in the test calls, because a file isn't the same as code typed interactively; Python doesn't echo the results of expression statements.

    % cat mod.py
    def adder(x, y):
        return x + y
    
    print adder(2, 3)
    print adder('spam', 'eggs')
    print adder(['a', 'b'], ['c', 'd'])
    
    % python mod.py
    5
    spameggs
    ['a', 'b', 'c', 'd']
  3. varargs. Two alternative adder functions are shown in the following code. The hard part here is figuring out how to initialize an accumulator to an empty value of whatever type is passed in. In the first solution, we use manual type testing to look for an integer and an empty slice of the first argument (assumed to be a sequence) otherwise. In the second solution, we just use the first argument to initialize and scan items 2 and beyond. The second solution is better (and frankly, comes from students in a Python course, who were frustrated with trying to understand the first solution). Both of these assume all arguments are the same type and neither works on dictionaries; as we saw in Chapter 2, + doesn't work on mixed types or dictionaries. We could add a type test and special code to add dictionaries too, but that's extra credit.

    % cat adders.py
    
    def adder1(*args):
        print 'adder1',
        if type(args[0]) == type(0):    # integer?
             sum = 0                    # init to zero
        else:                           # else sequence:
             sum = args[0][:0]          # use empty slice of arg1
        for arg in args:
            sum = sum + arg
        return sum
    
    def adder2(*args):
        print 'adder2',
        sum = args[0]               # init to arg1
        for next in args[1:]:
            sum = sum + next        # add items 2..N
        return sum
    
    for func in (adder1, adder2):
        print func(2, 3, 4)
        print func('spam', 'eggs', 'toast')
        print func(['a', 'b'], ['c', 'd'], ['e', 'f'])
    
    % python adders.py
    adder1 9
    adder1 spameggstoast
    adder1 ['a', 'b', 'c', 'd', 'e', 'f']
    adder2 9
    adder2 spameggstoast
    adder2 ['a', 'b', 'c', 'd', 'e', 'f']
  4. Keywords. Here is our solution to the first part of this one. To iterate over keyword arguments, use a **args for in the function header and use a loop like: for x in args.keys(): use args[x]

    % cat mod.py
    def adder(good=1, bad=2, ugly=3):
        return good + bad + ugly
    
    print adder()
    print adder(5)
    print adder(5, 6)
    print adder(5, 6, 7)
    print adder(ugly=7, good=6, bad=5)
    
    % python mod.py
    6
    10
    14
    18
    18
  5. and 6. Here are our solutions to Exercises 5 and 6, but Guido has already made them superfluous; Python 1.5 includes new dictionary methods, to do things like copying and adding (merging) dictionaries. See Python's library manual or the Python Pocket Reference for more details. X[:] doesn't work for dictionaries, since they're not sequences (see Chapter 2). Notice that if we assign (e = d) rather than copy, we generate a reference to a shared dictionary object; changing d changes e too.

    % cat dict.py
    
    def copyDict(old):
        new = {}
        for key in old.keys():
            new[key] = old[key]
        return new
    
    def addDict(d1, d2):
        new = {}
        for key in d1.keys():
            new[key] = d1[key]
        for key in d2.keys():
            new[key] = d2[key]
        return new
    
    % python
    >>> from dict import *
    >>> d = {1:1, 2:2}
    >>> e = copyDict(d)
    >>> d[2] = '?'
    >>> d
    {1: 1, 2: '?'}
    >>> e
    {1: 1, 2: 2}
    
    >>> x = {1:1}
    >>> y = {2:2}
    >>> z = addDict(x, y)
    >>> z
    {1: 1, 2: 2}
  6. More argument matching examples. Here is the sort of interaction you should get, along with comments that explain the matching that goes on:

    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 + positional varargs
    
    
    % python
    >>> f1(1, 2)                  # matched by position (order matters)
    1 2
    >>> f1(b=2, a=1)              # matched by name (order doesn't matter)
    1 2
    
    >>> f2(1, 2, 3)               # extra positionals collected in a tuple
    1 (2, 3)
    
    >>> f3(1, x=2, y=3)           # extra keywords collected in a dictionary
    1 {'x': 2, 'y': 3}
    
    >>> f4(1, 2, 3, x=2, y=3)     # extra of both kinds
    1 (2, 3) {'x': 2, 'y': 3}
    
    >>> f5(1)                     # both defaults kick in
    1 2 3
    >>> f5(1, 4)                  # only one default used
    1 4 3
    
    >>> f6(1)                     # one argument: matches "a"
    1 2 ()
    >>> f6(1, 3, 4)               # extra positional collected
    1 3 (4,)
I l@ve RuBoard Previous Section Next Section