[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:

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)
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 
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
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 
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