Monday, October 5, 2009

Python: input, raw_input, and inadvertently treating integers as strings

This is a "newbie" mistake, but these little details do tend to get in the way, which is why I'm posting my wee Python tutorial. If you know Python or programming, even reasonably well, this will probably seem way too simple to you. Just giving you a "heads up" so you don't waste your time.

I encountered a lesson that teaches storing conditionals using booleans. The code was presented like this:

young = age < 45 

slim = bmi < 22.0 
if young and slim: 
risk = "low" 
elif young and not slim: 
risk = "medium" 
elif not young and slim: 
risk = "medium" 
elif not young and not slim: 
risk = "high"
Of course, you can't really run this. If you try, you get this:
Traceback (most recent call last): 
File "assign_bool.py", line 1, in  
young = age < 45 
NameError: name 'age' is not defined 
I figured the solution was to modify the program to let me input the age and bmi, then print the results. I modified the code like this:
age = raw_input("Please enter your age: ")
bmi = raw_input("Please enter your bmi: ")

young = age < 45
slim = bmi < 22.0
if young and slim:
    risk = "low"
elif young and not slim:
    risk = "medium"
elif not young and slim:
    risk = "medium"
elif not young and not slim:
    risk = "high"

print risk
Like I said, if you have any real programming experience at all, you can already see my mistake. If not, read on. My modified code happily returned prompts for my age and bmi. Being scrupulously honest, I entered my correct age. I have no idea when my bmi is, so I made up a value. When I pressed enter, the value returned was "high". Just to make sure the program was working properly, I entered a young age and a low bmi. Egad! The return value was still "high". In fact, no matter what values I entered, "high" was always returned. This wasn't right. On the fly, I tried this change:
age = input("Please enter your age: ")
bmi = input("Please enter your bmi: ")
It seems very simple (and it is). Using raw_input, the data is always interpreted as a string, rather than the INT type I needed for the program to work. Since strings, rather than integers where input, Python worked it's way through the various tests and, since none of the other conditions matched, printed the result of the final clause which of course, was "high". input interprets what you enter as a python expression, which works, but isn't the best solution, since it can return a wide variety of object types. What's really needed is a way to input something that's always interpreted as a number. I did a bit of research and came up with the following solution, changing the first two lines of my program accordingly:
age = int(raw_input("Please enter your age: "))
bmi = int(raw_input("Please enter your bmi: "))
Now the program will always expect integers to be input for age and bmi. If you try to enter a string now, you'll get something like this:
Please enter your age: Fred
Traceback (most recent call last):
File "assign_bool.py", line 1, in 
age = int(raw_input("Please enter your age: "))
ValueError: invalid literal for int() with base 10: 'Fred'
Play with the different input types and see for yourself. Share/Bookmark

3 comments:

Please make comments.