简体   繁体   中英

How do I limit user input to specific integers, and keep track of exceptions, in Python 2.7?

EDIT: The suggested duplicate is incredibly helpful in regards to basic input validation. While it does cover a lot, my specific problem (failing to assign int(evaluation) to a variable) is only explicitly addressed here. I'm marking this separately in case anyone else has made a similarly silly mistake :)

I've spent the last few weeks playing with Python 2.7 and having a lot of fun. To learn more about while loops, I've created a small script which asks the user for an integer between 1 and 10.

My goal is to then be able to respond to cases in which the user responds with unexpected input, like a non-integer, or an integer outside the specified range. I've been able to fix a lot of my issues with help from other StackOverflow threads, but now I'm stumped.

First, I created a variable, idiocy , to keep track of exceptions. (The script is supposed to be sassy, but until I get it working, I'm the one it's making fun of.)

idiocy = 0

while 1:
    evaluation = raw_input("> ")
    try:
        int(evaluation)
        if evaluation < 1 or evaluation > 10:
            raise AssertionError
    except ValueError:
        idiocy += 1
        print "\nEnter an INTEGER, dirtbag.\n"
    except AssertionError:
        idiocy += 1
        print "\nI said between 1 and 10, moron.\n"
    else:
        if idiocy == 0:
            print "\nOkay, processing..."
        else:
            print "\nDid we finally figure out how to follow instructions?"
            print "Okay, processing..."
        break

As you can see, I'm trying to handle two different errors -- a ValueError for the input type, and an AssertionError for the integer range -- and keep track of how many times they're raised. (Really, I only care about knowing whether or not they've been raised at least once; that's all I need to insult the user.)

Anyways, when I run the script in its current form, the error response works just fine ('dirtbag' for non-integers, 'moron' for out-of-range). The problem is that even when I input a valid integer, I still get an out-of-range AssertionError .

I suspect that my issue has to do with my while logic, but I'm not sure what to do. I've added a break here or there but that doesn't seem to help. Any suggestions or blatant errors? Again, total Python beginner here, so I'm half winging it.

//If anyone has simpler, cleaner, or prettier ways to do this, feel free to let me know too. I'm here to learn!

Your problem is you're not saving the int version of evaluation to evaluation like this:

idiocy = 0

while 1:
    evaluation = raw_input("> ")
    try:
        evaluation = int(evaluation) <--- here
        if evaluation < 1 or evaluation > 10:
            raise AssertionError
    except ValueError:
        idiocy += 1
        print "\nEnter an INTEGER, dirtbag.\n"
    except AssertionError:
        idiocy += 1
        print "\nI said between 1 and 10, moron.\n"
    else:
        if idiocy == 0:
            print "\nDid we finally figure out how to follow instructions?"
            print "Okay, processing..."
        else:
            print "\nOkay, processing..."

If you wanted to track the types of exceptions raised, you could use collections.Counter for idiocy and change the code like this:

from collections import Counter

idiocy = Counter()

while 1:
    evaluation = raw_input("> ")
    try:
        evaluation = int(evaluation)
        if evaluation < 1 or evaluation > 10:
            raise AssertionError
    except ValueError as e:
        idiocy[e.__class__] += 1 
        print "\nEnter an INTEGER, dirtbag.\n"
    except AssertionError as e:
        idiocy[e.__class__] += 1
        print "\nI said between 1 and 10, moron.\n"
    else:
        if idiocy == 0:
            print "\nDid we finally figure out how to follow instructions?"
            print "Okay, processing..."
        else:
            print "\nOkay, processing..."

>>> idiocy
Counter({AssertionError: 2, ValueError: 3})

And you can access the error counts by key like idiocy[AssertionError]

You have int(evalutation) , but you're not assigning it to anything.

Try

try:
    evaluation = int(evaluation)
    assert 0 < evaluation < 10
except ValueError:
    ...
except AssertionError:

Your range test can be refactored as

assert 1 <= evaluation <= 10

You could keep your insults in a dictionary

insults = {AssertionError : "\nI said between 1 and 10, moron.\n",
           ValueError : "\nEnter an INTEGER, dirtbag.\n"
           }

And write the try/except like this

try:
    ...
except (AssertionError, ValueError) as e:
    print(insults[type(e)])

When you change the user input to an int, you need to assign it to something

evaluation = int(evaluation)

assert was meant for debugging - you are using it incorrectly.

  • You should use TypeError for non-integer repsonses - the type is wrong.
  • You use ValueError for responses outside of a range - the value is wrong

In your code: int(evaluation) is not typecasting evaluation variable to int type. The output is:

> 2
<type 'str'>
I said between 1 and 10, moron.

Try this:

idiocy = 0

while 1:
    try:
        evaluation = int(raw_input("> "))
        if evaluation < 1 or evaluation > 10:
            raise AssertionError
    except ValueError:
        idiocy += 1
        print "\nEnter an INTEGER, dirtbag.\n"
    except AssertionError:
        idiocy += 1
        print "\nI said between 1 and 10, moron.\n"
    else:
        if idiocy == 0:
            print "\nOkay, processing..."
        else:
            print "\nDid we finally figure out how to follow instructions?"
            print "Okay, processing..."
        break

By the way you can use tuple to store all your exceptions. Example:

idiocy = 0

all_exceptions = (ValueError, AssertionError)
while 1:
    try:
        evaluation = int(raw_input("> "))
        if evaluation < 1 or evaluation > 10:
            raise AssertionError("\nI said between 1 and 10, moron.\n")
    except all_exceptions as e:
        idiocy += 1
        print str(e)
    else:
        if idiocy == 0:
            print "\nOkay, processing..."
        else:
            print "\nDid we finally figure out how to follow instructions?"
            print "Okay, processing..."
        break

Hope it helps.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM