1

Python Version - 2.7.11

I am following Zed Shaw's Learn Python the Hard Way and am currently at Exercise 21

I am trying to modify the code so that the script prompts the user to enter the values (age, height etc) instead of hard coding them.

With everything else remaining the same, I modified this line:

age = add(float(raw_input('Enter 2 numbers')))

..and entered two numbers (5, 1) which resulted in the following error:-

ValueError: invalid literal for float(): 5,2

I replaced float(raw_input()) with int(raw_input()) and that gave the following error

ValueError: invalid literal for int() with base 10: '5,1'

Could someone please advise me where I am going wrong?

pb_ng
  • 361
  • 1
  • 5
  • 19
  • 2
    Is there any particular reason you are learning Python 2 instead of the modern version? BTW, LPTHW is not recommended, for various reasons. Please see [What tutorial should I read?](http://sopython.com/wiki/What_tutorial_should_I_read%3F) – PM 2Ring Jun 06 '16 at 06:45
  • 1
    @PM2Ring Agreed on second point "*its structure tends to lead people into asking premature questions*" Such as how to read two numbers from one input when the exercise implied doing one number per input :) – OneCricketeer Jun 06 '16 at 06:51

4 Answers4

3

You need to split your input into two numbers before converting these to float; use str.split():

while True:
    ages = raw_input('Enter 2 numbers')
    try:
        age1, age2 = [float(age) for age in ages.split(',')]
        break
    except ValueError:
        print("Sorry, you did not enter two numbers, try again")

add(age1, age2)

I've added a while True loop to keep asking for correct input whenever there is an error; the ValueError exception is raised both if float() fails to convert a value or if there are not enough or too many inputs given. If conversion succeeds and there are exactly two values to assign to age1 and age2, no exception is raised and the break statement exits the endless loop. See Asking the user for input until they give a valid response for more details on how this works.

Community
  • 1
  • 1
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Thanks - but when the following piece of code tries to run `print "Age: %d, Height: %d, Weight: %d, IQ: %d" % (age, height, weight, iq)` it throws the error `TypeError: %d format: a number is required, not str` – pb_ng Jun 06 '16 at 06:44
  • 1
    @pb_ng: that's not caused by the code in this answer, because the loop can't end with either `age1` or `age2` set to a string. – Martijn Pieters Jun 06 '16 at 06:46
  • @pb_ng: at least *one* of the values of `age`, `height`, `weight` or `iq` is a string, not an integer or float. You'll have to fix that in your code. – Martijn Pieters Jun 06 '16 at 06:47
2

I think you might have meant to split the values?

nums = map(float, raw_input('Enter 2 numbers').split(','))
age = add(*nums) 

map will apply a function, in this case float() across a collection of items, which is a list of strings as a result of split().

*nums is some variant of tuple-unpacking. It takes a collection of items, and "expands" them into the arguments needed for the function.

Alternatively, this also works, but it is simply more to type.

age = add(nums[0], nums[1]) 
OneCricketeer
  • 179,855
  • 19
  • 132
  • 245
  • missing conversion to float/int, also there is no indication that OP's add() function accepts a list – Niklas R Jun 06 '16 at 06:30
  • I used the split and it resulted in the following error `TypeError: int() argument must be a string or a number, not 'list'` – pb_ng Jun 06 '16 at 06:32
  • That makes sense. My bad – OneCricketeer Jun 06 '16 at 06:34
  • 3
    Can you add an explanation as to what `map()` and `*nums` do in your answer? I know most visitors here just copy and paste, but for those few that try to *understand* what they are copying, it'd be helpful. – Martijn Pieters Jun 06 '16 at 06:37
  • Exactly - I haven't yet come across the terms `map()` and `nums` so a little information about them would be very helpful. – pb_ng Jun 06 '16 at 06:39
  • @pb_ng `nums` == "numbers" – OneCricketeer Jun 06 '16 at 06:44
  • Using `*` in a call is not called tuple-unpacking. That's a term usually applied to *assignment* where the left-hand target is a tuple (`var1, var2, var3 = iterable_object_with_three_values`). There is no good name for the call syntax yet. "Variable arguments", "positional argument expansion", etc. have all been applied here. – Martijn Pieters Jun 06 '16 at 06:52
  • @MartijnPieters From my understanding, it does unpack the collection, so that's what I'm going to call it :) – OneCricketeer Jun 06 '16 at 06:56
  • That's your prerogative, but take into account that when you talk to other experienced Python developers, that they'll assume you are talking about assignment instead. – Martijn Pieters Jun 06 '16 at 07:14
0

try this.

age1,age2=(float(x) for x in raw_input('Age_1, Age_2: ').split(','))
print add(age1,age2)

.split(n) will create a list from a string by splitting the string at each index of n. Code is the same as:

n = raw_input('Age_1, Age_2')
n = n.split(',')
age1 = float(n[0])
age2 = float(n[1])
print add(age1, age2)
TheLazyScripter
  • 2,541
  • 1
  • 10
  • 19
0

If you would like the user to input multiple values you will need to change your code up. As raw_input() can only unpack one value.

for example, you cannot input a tuple and have raw_input() unpack it

>>> a, b = raw_input('enter two numbers: ')
>>> enter two numbers: 69, 420
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: too many values to unpack

instead maybe try this:

>>>variables = []
>>>for i in range(len(<How many inputs does your function need>)):
>>>   variables.append(float('enter variable{}:'.format(i)))
>>>
>>>age = add(variable[0], variable[1]... variable[n])

or as others have noted try to parse your input with string manipulation:

'string'.split()

.split method is very handy. check out the python wikibooks for an overview and examples of string methods

https://en.wikibooks.org/wiki/Python_Programming/Strings

  • 1
    `a, b = raw_input('enter two numbers')` followed by entering `ab` would work, because you *can* unpack a string with two characters in them. Iterable assignment works with any iterable, and a string is an iterable. – Martijn Pieters Jun 06 '16 at 06:48