[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