Earlier today I answered Timetable viewer, where one of my recommendations was to make a get_input
function.
However, this hasn't been the first time I've recommended making a bespoke get_input
function.
This function should get user input, until it is valid. This may be any input, or any number in a specific range. The arguments customize how it works, such as working with strings or integers. The function should repeatedly prompt the user for specific input, until a valid input is entered. In the case case of valid input we should return that data, so the end user can use it.
Since it's quite a common function, with a lot of uses, I decided to make a generic version of the function, that should cover most use cases. I decided to make two functions, as strings don't need to be converted, however when changing to numbers, you'd have to duplicate a lot of arguments.
def build_input(
prompt=None,
*,
errors=None,
values=None,
process=None,
wanted=None,
end=None
):
prompt = prompt or ''
process = process or (lambda v: v)
errors = errors or tuple()
if values is None:
wanted = wanted or (lambda v: True)
else:
values = list(values)
prompt += '[{}] '.format('/'.join(str(i) for i in values))
wanted = wanted or (lambda v: v in values)
values = set(values)
if end is not None:
prompt += end
elif values:
prompt += '\n> '
def ask():
while True:
value = input(prompt)
try:
value = process(value)
except errors:
continue
if wanted(value):
return value
return ask
def build_number_input(
prompt=None,
*,
errors=ValueError,
values=None,
process=int,
wanted=None,
end=None
):
return build_input(
prompt,
errors=errors,
values=values,
process=process,
wanted=wanted,
end=end
)
I have a couple of concerns:
build_number_input
spans 17 lines, for a function definition and a function call. Is there a better way to define this?- Are there a better way to style my function definitions? I think they may not be PEP8 compliant, but couldn't think of anything nicer to read.
- Are there any common options that you think should be added?
Below are a couple of ways to use the above functions, and a sample run:
name_input = build_input('What is your name? ')
age_input = build_number_input('What is your age? ')
day_input = build_number_input('Day: ', values=[1, 2, 3, 4, 5])
again_input = build_input('Again? ', values='yn', process=lambda v:v.lower())
print('Hello, {}! You are {}.'.format(name_input(), age_input()))
print('You want day {}'.format(day_input()))
print('You {}want to go again.'.format('' if again_input() == 'y' else "don't "))
What is your name? Peilonrayz
What is your age? 20.5
What is your age? 20a
What is your age? 20
Hello, Peilonrayz! You are 20.
Day: [1/2/3/4/5]
> 6
Day: [1/2/3/4/5]
> 0
Day: [1/2/3/4/5]
> 55
Day: [1/2/3/4/5]
> five
Day: [1/2/3/4/5]
> 5
You want day 5
Again? [y/n]
> yeah
Again? [y/n]
> Nope?
Again? [y/n]
> N
You don't want to go again.
float
rather thanint
. \$\endgroup\$