[Tutor] Most pythonic input validation
Christian Witts
cwitts at compuscan.co.za
Fri Oct 16 12:20:51 CEST 2009
Katt wrote:
>
>> Message: 3
>> Date: Thu, 15 Oct 2009 16:50:57 +0100
>> From: Rich Lovely <roadierich at googlemail.com>
>> To: Wayne Werner <waynejwerner at gmail.com>
>> Cc: "tutor at python.org" <Tutor at python.org>
>> Subject: Re: [Tutor] Most pythonic input validation
>> Message-ID:
>> <f0b4202b0910150850w7fe680c0v400bc5d432f716b at mail.gmail.com>
>> Content-Type: text/plain; charset=windows-1252
>>
>> 2009/10/15 Wayne Werner <waynejwerner at gmail.com>:
>>> Hi,
>>> I'm writing a text based menu and want to validate the user input. I'm
>>> giving the options as integers, and I want to make sure the user
>>> enters a
>>> proper value.
>>> Here's what I've got so far:?http://pastebin.com/m1fdd5863
>>> I'm most interested in this segment:
>>> ?? ?while True:
>>> ?? ? ? ?choice = raw_input(prompt)
>>> ?? ? ? ?if valid_choice(choice, 0, len(options)-1):
>>> ?? ? ? ? ? ?break
>>> ?? ?return choice
>>> Is that the most pythonic way of validating? Is there a better way?
>>> As an aside, in the valid_choice function I know I could do:
>>> if not choice in range(min, max)
>>> but I figured a comparison would probably be the better choice,
>>> correct?
>>> Thanks,
>>> Wayne
>>> --
>>> To be considered stupid and to be told so is more painful than being
>>> called
>>> gluttonous, mendacious, violent, lascivious, lazy, cowardly: every
>>> weakness,
>>> every vice, has found its defenders, its rhetoric, its ennoblement and
>>> exaltation, but stupidity hasn?t. - Primo Levi
>>>
>>> _______________________________________________
>>> Tutor maillist ?- ?Tutor at python.org
>>> To unsubscribe or change subscription options:
>>> http://mail.python.org/mailman/listinfo/tutor
>>>
>>>
>>
>> The most pythonic way would be to use a try except block:
>>
>> while True:
>> choice = raw_input(prompt)
>> try:
>> options[int(choice)]
>> except (KeyError, IndexError, TypeError):
>> print "Invalid input, try again."
>> continue
>> return choice
>>
>>
>> Also, did you want to convert choice to an int at some point? You
>> appear to be comparing it to a number in valid_choice(), but it will
>> be passed out of the method as a str.
>>
>> Hence I've added a conversion to int, and I'm catching KeyError (for
>> dicts), IndexError (for lists), and TypeError, for when int(choice)
>> fails.
>>
>> This is a principle called "It's Easier to Ask Forgiveness than
>> Permission" (EAFP), which is one of the pythonic principles.
>>
>>
>> Hope that helps.
>> --
>> Rich "Roadie Rich" Lovely
>
> As I am a new programmer I am specifically trying to pay attention to
> when you guys discuss making thing more python like.
>
> I am a bit confused though on a couple things in this code. Probably
> since I have not dealt with it as of yet.
>
> The first is the while statement. I have made a successful menu
> selection but my while statement is:
> while prompt != 0:
> 0 of course meaning exit. Does "while True:" mean the same?
>
> Second is the input statement. Could you not just put choice =
> int(raw_input(prompt)) instead of using two different statements? Or
> is it that my example will return as string?
>
> The third is the "try" statement. How is this different from the
> "for" loop or "if" loop?
>
> The fourth is except (KeyError, IndexError, TypeError): why do you
> check for three different types of errors?
>
> Thanks in advance,
>
> Katt
>
>
> _______________________________________________
> Tutor maillist - Tutor at python.org
> To unsubscribe or change subscription options:
> http://mail.python.org/mailman/listinfo/tutor
>
1) `while True` will result in an infinite loop unless you test for your
prompt condition inside the loop and if it's true then use a break
statement to exit the loop, eg.
while True:
if prompt == 0:
break
2) If you were to put the `choice = int(raw_input(prompt))` into one
line, remember to put it in a try/except block as you could be casting
an alphanumeric into an integer. The reasoning behind putting it on two
lines is to increase readability and so that you have a variable
`choice` which contains the actual input in case you wanted to use it
for something if it causes an exception, eg.
choice = raw_input(prompt)
try:
options[int(choice)]
except (KeyError, IndexError, TypeError):
print '%s is not a valid choice' % choice
3) If you start a `try` block it is because you want to handle any
errors occurring from the statements / expressions in the block itself.
It is not a loop, it just runs through once completely or until it
receives the first exception and in that case then moves onto the
`except` section
4) The three exceptions lists are for various errors that might have
occurred.
The KeyError is if `options` is a dictionary and the key (contained in
choice) is not in your dictionary, although for a dictionary I would
rather write `if int(choice) in options:`.
The IndexError is if `options` is a list and your choice was supposed to
be the index that you want to seek to, eg.
options = ['Exit', 'Start New Game', 'High Scores']
choice = raw_input(prompt) # lets say you use the number 3 here
try
options[int(choice)]
except IndexError:
print 'Selection out of range, please use a number between 0 and %s'
% (len(options)-1)
Counting starts from zero so there are 0, 1, 2 as valid choices in this
example.
The TypeError, should be a ValueError, is for catching conversion
errors. If you supply a choice of 'a' and try and convert that to an
integer it will throw a ValueError letting you know that what you are
trying to convert is not an integer. TypeError will catch a NoneType
conversion which you won't be able to type in on the console.
Hope that helps.
--
Kind Regards,
Christian Witts
More information about the Tutor
mailing list