Katt wrote:

Message: 3
Date: Thu, 15 Oct 2009 16:50:57 +0100
From: Rich Lovely <[email protected]>
To: Wayne Werner <[email protected]>
Cc: "[email protected]" <[email protected]>
Subject: Re: [Tutor] Most pythonic input validation
Message-ID:
<[email protected]>
Content-Type: text/plain; charset=windows-1252

2009/10/15 Wayne Werner <[email protected]>:
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 ?- [email protected]
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  -  [email protected]
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


_______________________________________________
Tutor maillist  -  [email protected]
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor

Reply via email to