[Tutor] comapring lists

Danny Yoo dyoo at hkn.eecs.berkeley.edu
Fri Dec 3 09:38:48 CET 2004



On Thu, 2 Dec 2004, Jacob S. wrote:

> If you or anybody else is interested, I've written a script for codes like
> kids in junior high use to write notes to each other with...

Hi Jacob,

Cool!  Do you mind if I make some comments on the code?  If you do mind...
um... skip this message.  *grin*


The main body of the program feels a bit too long: it screams to be broken
into a few helper functions.  I see that there are two critical variables
that are used to figure out which part of the program comes next:


###
unordo = raw_input('Are we going to decipher or cipher? ')
type = raw_input('Which type of code would you like? ').lower()

if type == 'mixed letters':
    if unordo == 'cipher':
        # ... do mixed letter ciphering
    if unordo == 'decipher':
        # ... do mixed letter deciphering
if type == 'insideout':
    if unordo == 'cipher':
        # ... do insideout ciphering
    if unordo == 'decipher':
        # ... do mixed letter decipering
# ... rest of the program follows similar structure
###



In a case like this, we can break the program into separate functions,
like this:

###
def dispatchOnTypeAndUnordo(type, unordo):
    if type == 'mixed letters':
        if unordo == 'cipher':
            mixedLetterCipher()
        if unordo == 'decipher':
            mixedLetterDecipher()
    if type == 'insideout':
        if unordo == 'cipher':
            insideoutCipher()
        if unordo == 'decipher':
            insideoutDecipher()
    # ... rest of the program follows similar structure
###

We make each 'body' of the inner "if"'s into their own functions, like
'mixedLetterCipher()'.  This restructuring doesn't improve the program's
performance at all, but it does help readability: the main improvement is
to make the overall shape of the program all visible at once.


This structural change also paves the way for a "table-driven" way to
implement a decision tree.  Experienced programmers really try to avoid
code that looks like "if/if/if/if/if..." because that's probably some kind
of repeating structure that we can take advantage of.


The logic on the function dispatchOnTypeAndUnordo() has an internal rhythm
that we can capture as a data structure.  Here's a dictionary that tries
to capture the essentials of the beat:

###
dispatchTable = { 'mixed letters': (mixedLetterCipher,
                                    mixedLetterDecipher),
                  'insideout'    : (insideOutCipher,
                                    insideOutDecipher),
           ## ... rest of the dictionary follows similar structure
                }
###

[Note: the values in this dictionary --- the function names --- are
intentionally without parentheses.  We don't want to "call" the functions
just yet, but just want to store them off.]


If we have a dispatch table like this, then the dispatchOnTypeandUnordo()
magically dissolves:

###
def dispatchOnTypeAndUnordo(type, unordo):
    (cipherFunction, decipherFunction) = dispatchTable[type]
    if unordo == 'cipher':
        cipherFunction()
    elif unordo == 'decipher':
        decipherFunction()
###


This is a "table-driven" or "data-driven" approach.  The choices available
to the program have been migrated away from the explicit, separate 'if'
statements, and now really live as part of the 'dispatchTable' dictionary.


Does this make sense so far?  Please feel free to ask questions.



More information about the Tutor mailing list