[Tutor] Is my style OK in this elementary student exercise?

Lie Ryan lie.1296 at gmail.com
Sat Jul 4 22:53:06 CEST 2009


Angus Rodgers wrote:
>> Date: Sat, 04 Jul 2009 13:26:12 +0100
>> From: Angus Rodgers <angusr at bigfoot.com>
>> Message-ID: <vrhu451924b136aea0ivadnlqc4h7uqavu at 4ax.com>
>>
>> <http://python.pastebin.com/d7e245e0f>   (retention: 1 day)
> 
> This is just a quick(ish!) response to the feedback so far.
> 
> I realise, now, that I should have quoted what the exercise in the
> book was asking for, to explain why my code is more elaborate than
> the minimum that would be required to solve the problem at hand.
> 
>>From the book (2nd ed., p. 151):
> 
>  "[...] we recommend that the reader convert his or her code to
>  functions that can be used in future exercises."
> 
> This requirement was uppermost in my mind.

If it is the top requirement, then your code is not general enough as it
can only ask for dictionaries. A general solution would be at least
something like this: (now talk about bloat and overdesigning...)

#!/usr/bin/env python

import re
from functools import partial

''' Like Swiss Army. It does everything.
    Includes batteries and kitchen sink.
    Caveat: written at 3AM in the morning.
'''

class PromptError(Exception): pass

def prompt(prompt='? ',
           reprompt='Invalid input. Try again.',
           validate=str,
           postprocess=str,
           tries=3,
           catchlist=(ValueError,),
          ):
    ''' prompt the user for input, validate, and return the result
        postprocess is called before returning the value
        if number of tries exceeds `tries` raise PromptError. Set
        tries to -1 to prompt infinitely
    '''
    while tries != 0:
        inp = raw_input(prompt)
        try:
            validate(inp)
        except catchlist, e:
            print reprompt
            tries -= 1
        else:
            return postprocess(inp)
    else:
        raise PromptError('Maximum number of tries exceeded')

def expecting(s, expected=[], errmess='Invalid input'):
    ''' return True if `s` matches any regex pattern in `expected`
        raises ValueError otherwise.
    '''
    for pat in expected:
        if re.compile(pat+'$', re.IGNORECASE).match(s):
            return True
    else:
        raise ValueError(errmess)

def convert(s, convtab):
    ''' convert `s` into convtab's key '''
    for target, pats in convtab.iteritems():
        for pat in pats:
            if re.compile(pat+'$', re.IGNORECASE).match(s):
                return target
    else:
        raise ValueError('Cannot convert')

def chain(*rings):
    ''' Calls a list of function and return their
        return values as a tuple
    '''
    def _chain():
        return tuple(ring() for ring in rings)
    return _chain

def serial_prompt(mainprompt,
                  cont_prompt='Continue? ',
                  postprocess=lambda x: x,
                 ):
    ''' Prompts for a series of values, with 'continue?'s
        between each prompt.
        Return values of the prompts are collected in a list
        and passed to `postprocess`.
    '''
    def _serial_prompt():
        ret = [mainprompt()]
        while get_bool(cont_prompt):
            ret.append(mainprompt())
        return postprocess(ret)
    return _serial_prompt

trues = ['1', 'ye?s?', 'tr?u?e?']
falses = ['0', 'no?', 'fa?l?s?e?']
bools = trues + falses
expecting_bool = partial(expecting, expected=bools)
convert_bool = partial(convert, convtab={True: trues, False: falses})
get_bool = partial(prompt,
                   validate=expecting_bool,
                   postprocess=convert_bool,
                  )

get_key = prompt
get_value = partial(prompt,
                    validate=int,
                    postprocess=int,
                   )
get_kv = chain(partial(get_key, prompt='key (str): '),
               partial(get_value, prompt='value (int): '),
              )

get_dict = serial_prompt(get_kv, postprocess=dict)

print get_bool('bool: ')
print get_key('key (str): ')
print get_value('value (int): ')
print get_kv()
print get_dict()



More information about the Tutor mailing list