DekGenius.com
[ Team LiB ] Previous Section Next Section

12.4 A Second Example: Intersecting Sequences

Let's look at a second function example that does something a bit more useful than multiplying arguments, and further illustrates function basics.

In Chapter 10, we saw a for loop that collected items in common in two strings. We noted there that the code wasn't as useful as it could be because it was set up to work only on specific variables and could not be rerun later. Of course, you could cut and paste the code to each place it needs to be run, but this solution is neither good nor general—you'd still have to edit each copy to support different sequence names, and changing the algorithm then requires changing multiple copies.

12.4.1 Definition

By now, you can probably guess that the solution to this dilemma is to package the for loop inside a function. Functions offer a number of advantages over simple top-level code:

  • By putting the code in a function, it becomes a tool that can be run as many times as you like.

  • By allowing callers to pass in arbitrary arguments, you make it general enough to work on any two sequences you wish to intersect.

  • By packaging the logic in a function, you only have to change code in one place if you ever need to change the way intersection works.

  • By coding the function in a module file, it can be imported and reused by any program run on your machine.

In effect, wrapping the code in a function makes it a general intersection utility:

def intersect(seq1, seq2):
    res = [  ]                        # Start empty.
    for x in seq1:               # Scan seq1.
        if x in seq2:            # Common item?
            res.append(x)        # Add to end.
    return res

The transformation from the simple code of Chapter 10 to this function is straightforward; we've just nested the original logic under a def header and made the objects on which it operates passed-in parameter names. Since this function computes a result, we've also added a return statement to send a result object back to the caller.

12.4.2 Calls

Before you can call the function, you have to make the function. Run its def statement by typing it interactively, or by coding it in a module file and importing the file. Once you've run the def one way or another, you call the function by passing any two sequence objects in parenthesis:

>>> s1 = "SPAM"
>>> s2 = "SCAM"

>>> intersect(s1, s2)                   # Strings
['S', 'A', 'M']

Here, the code passes in two strings, and gets back a list containing the characters in common. The algorithm the function uses is simple: "for every item in the first argument, if that item is also in the second argument, append the item to the result." It's a little shorter to say that in Python than in English, but it works out the same.

12.4.3 Polymorphism Revisited

Like all functions in Python, intersect is polymorphic—it works on arbitrary types, as long as they support the expected object interface:

>>> x = intersect([1, 2, 3], (1, 4))    # Mixed types
>>> x                                   # Saved result object
[1]

This time, we pass in different types of objects to our function—a list and a tuple (mixed types)—and it still picks out the common items. Since you don't have to specify the types of arguments ahead of time, the intersect function happily iterates through any kind of sequence objects you send it, as long as they support the expected interfaces.

For intersect, this means that the first argument has to support the for loop, and the second has to support the in membership test—any two such objects will work. If you pass in objects that do not support these interfaces (e.g., passing in numbers), Python will automatically detect the mismatch and raise an exception for you—exactly what you want, and the best you could do on your own if you coded explicit type tests. The intersect function will even work on class-based objects you code, which you will learn how to build in Part VI.[1]

[1] FOOTNOTE MISSING

12.4.4 Local Variables

The variable res inside intersect is what in Python is called a local variable— a name that is only visible to code inside the function def, and only exists while the function runs. In fact, because all names assigned in any way inside a function are classified as local variables by default, nearly all the names in intersect are local variables:

  • Because res is obviously assigned, it is a local variable.

  • Because arguments are passed by assignment, so too are seq1 and seq2.

  • Because the for loop assigns items to a variable, so is name x.

All these local variables appear when the function is called, and disappear when the function exits—the return statement at the end of intersect sends back the result object, but name res goes away. To fully understand the notion of locals, though, we need to move on to Chapter 13.

    [ Team LiB ] Previous Section Next Section