Session 28

Dictionaries, Design, and Parameters

CS 1510
Introduction to Computing

Opening Exercise

Back in Session 20, we built a function called multi_find(), which we used on Homework 9. Let's refresh our memory on how it works.

    def multi_find(source, target, start, end):
        result = ''
        pos = start

        while pos < end:
            next_pos = source.find(target, pos, end)
            # 1
            if next_pos == -1:
            result += (str(next_pos) + ',')
            # 2
            pos = next_pos + 1

        if result == '':
            return result
        return result[:-1]

Trace the code for the call

    multi_find('abcdabccabacdeacbe', 'ab', 2, 12)
Write down the value of pos and next_pos every time you reach #1.
Write down the value of result every time you reach #2


Let's run the code and find out... Now we can see that find() lets the code speed through the source string, focusing on the matches. Try changing the 12 to 100!

Several students have told me "I don't really understand what this function does..." What can you do when you find yourself in this position?

All programmers occasionally run into code that baffles them. We all use techniques like this to get out of the dark. You, too, can be the source of your own enlightenment.

Making multi_find() More Pythonic

When we wrote multi_find(), strings and files were the only collections we knew about, and we had only begun to write our own functions. Now that we know lists and understand functions pretty well, we can make the function more Python-like and work more like its inspiration, the string method find().

Return Type.   multi_find() returns a string, but that was a product of our limited Python knowledge. A list is a much more useful return type. That's an easy improvement to make, affecting only three points in the code

The result is a straightforward function that's easier for client code to use.

    >>> multi_find('abcdabccabacdeacbe', 'ab', 2, 100)
    [4, 8]
    >>> multi_find('abcdabccabacdeacbe', 'b', 2, 100)
    [5, 9, 16]
    >>> multi_find('abcdabccabacdeacbe', 'a', 0, 100)
    [0, 4, 8, 10, 14]

Optional Arguments.   If we want to search all the way to the end of a string, the find() method allows us to leave off the last argument. The default value is the length of the string.

    >>> len('abcdabccabacdeacbe')
    >>> 'abcdabccabacdeacbe'.find('a', 6, 18)
    >>> 'abcdabccabacdeacbe'.find('a', 6)

If we want to search from the beginning of the string, we can even leave off the second argument. The method uses 0 as the default value.

    >>> 'abcdabccabacdeacbe'.find('a', 9)
    >>> 'abcdabccabacdeacbe'.find('a', 0)
    >>> 'abcdabccabacdeacbe'.find('a')

We can do the same thing by giving a parameter a default value in the function header. Here is our current header for multi_find():

    def multi_find(source, target, start, end):

Making start default to 0 is as easy as this:

    def multi_find(source, target, start=0, end):

We also need to give a default value to end. There are two reasons:

... look at "Check Yourself" on Page 369 of the text.

What is the default value for end? It is the length of the string to be searched, len(source). But if we try that...

    def multi_find(source, target, start=0, end=len(source)):

We get an error:

    Traceback (most recent call last):
      File "/Users/wallingf/home/teaching/cs1510/web/sessions/session28/", line 1, in 
        def multi_find(source, target, start=0, end=len(source)):
    NameError: name 'source' is not defined

The variable source does not exist until the function body executes. (You will learn why when you take CS 3540 Programming Languages and Paradigms.) So we have to write code to handle that case:

    def multi_find(source, target, start=0, end=None):
        if end == None:
            end = len(source)

This uses the None that we have seen a time or two as a sentinel value. If it is ever the value of end, then we know the user did not pass four values, and the function should search all the way to the end of source.

This works nicely!

    >>> multi_find('abcdabccabacdeacbe', 'ab', 2, 100)
    [4, 8]
    >>> multi_find('abcdabccabacdeacbe', 'ab', 2)
    [4, 8]
    >>> multi_find('abcdabccabacdeacbe', 'ab', 0)
    [0, 4, 8]
    >>> multi_find('abcdabccabacdeacbe', 'ab')
    [0, 4, 8]

I like languages that let me create code that works like the built-in features of the language. Python gives us that freedom on occasion.

Dictionaries in the Lab

In Lab 14, you got your first official experience using dictionaries in a program, using this data file. Let's step through it...

With just these two dictionaries, we can begin to answer many interesting questions. Some are just for fun, such as The Six Degrees of Kevin Bacon, a movie watcher's pastime from a few years ago. The Oracle of Bacon implements a simple look-up. Can you use your two dictionaries to implement something similar?

Wrap Up

Eugene Wallingford ..... ..... December 4, 2014