1

I am new to the python and My program is a simple addition program where it can add any number input by user(int or float) and the loop stops on entering q. Now my problem is that I keep getting "ValueError", every time I enter some numbers and then enter q to stop.

I have used eval() function to determine the datatype of the input data entered. and i have got my addition inside an infinite while loop that breaks on entering q.

This is my code:

sum,sum_i,c=0,0,0
sum_f=0.0

print("Enter q/Q to stop entering numbers.")
while True:
    a=input("Enter number: ")
    try:
        t= eval(a)
        print(type(t))
    except (NameError, ValueError):
        pass

    if(type(t)==int):
        sum_i=sum_i+int(a)
        c=c+1

    elif(type(t)==float):
        sum_f=sum_f+float(a)
        c=c+1

    elif (type(t)==str):
        if (a=='q'or a=='Q'):
            break

    else:
            print("Invalid data entered. Please enter a number to add or q/Q to quit. ")

sum= sum_i+ sum_f
print("You have entered ",c," numbers and their sum is: ",sum)

My output is supposed to provide the sum of the numbers entered on entering q, but this is what i get:

Enter q/Q to stop entering numbers.
Enter number: 3
<class 'int'>
Enter number: 5.5
<class 'float'>
Enter number: 12
<class 'int'>
Enter number: q
Traceback (most recent call last):
  File "/home/netvarth/py test/sum.py", line 14, in <module>
    sum_i=sum_i+int(a)
ValueError: invalid literal for int() with base 10: 'q'
3
  • A general good practice is to use import ast, ast.literal_eval() instead of eval(), for security reasons Commented Jan 17, 2019 at 7:41
  • 1
    @Archie I know this is not really production code, but never use eval() on raw input from the user. The user can just input something like sys.exit(0) and shutdown your system Commented Jan 17, 2019 at 7:44
  • eval('q') -> NameError; t remains what it was before. If it was int, you will try int('q') which yields your ValueError. Commented Jan 17, 2019 at 7:49

3 Answers 3

2

Here is a refactoring using nested try/except which solves the problem somewhat more succinctly and Pythonically.

#!/usr/bin/env python3

nums = list()
while True:
    # Usability tweak: Trim surrounding whitespace
    a = input("Enter number: ").strip()
    try:
        t = int(a)
    except ValueError:
        try:
            t = float(a)
        except ValueError:
            if a in ('q', 'Q'):
                break
            print("Invalid data entered. Please enter a number or q/Q to quit.")
            continue
    nums.append(t)
print("You have entered {0} numbers and their sum is {1}".format(
    len(nums), sum(nums)))
Sign up to request clarification or add additional context in comments.

Comments

1

two things: first to check for a type of something it is more pythonian to use

   isinstance(t, int)

but the second thing is where your code fails.

If you evaluate a literal you will get most likely a name error since the variable is not defined anywhere. However if you enter 'c' for example you get something weird entirely. Since the variable c is defined you won't get a name error but it will still fail when casting the literal 'c' to int.

you could use a regular expression to check if the input is a number or not

for example like so.

    if re.match('(\d+(\.\d+)?)', a):
        try:
            t = eval(a)
            print(type(t))
        except (NameError, ValueError):
            pass
    elif a == 'q' or a == 'Q':
        break
    else:
        continue

    if isinstance(t, int):
        sum_i = sum_i + int(a)
        c = c + 1

    elif isinstance(t, float):
        sum_f = sum_f + float(a)
        c = c + 1
    else:
        print("Invalid data entered. Please enter a number to add or q/Q to quit. ")

4 Comments

first you check if the input string matches the pattern for integer or float \d: digit +: at least one ?: not mandatory and if the input value matches the pattern you can evaluate it to int or float if this is not the case we assume its a string and are able to check for your exit condition
can't i use isinstance() without the eval() part? i got error on trying.
I took out the try block and instead added the if part for int and float under the regex if. My output: Enter q/Q to stop entering numbers. Enter number: 3 Enter number: 5.8 Enter number: 15 Enter number: q output ends there.
I don't quite follow you. Does the program fail? What is the output you get? For me it works file, if I enter the numbers you suggested I get the result You have entered 3 numbers and their sum is: 23.8
0

Your problem is in using eval. If it cannot parse a string as a variable, it should fail, but in your case you already have a t floating around in the namespace. t keeps its old identity as, say, an int, but then you try to add a (a string) to a number.

This code should work:

sum,sum_i,c=0,0,0
sum_f=0.0

print("Enter q/Q to stop entering numbers.")
while True:
    a=input("Enter number: ")
    try:
        t = int(a)
        sum_i=sum_i+int(a)
        c=c+1
        print(type(t))
        continue
    except ValueError:
        pass

    try:
        t = float(a)
        sum_f=sum_f+int(a)
        c=c+1
        print(type(t))
        continue
    except ValueError:
        pass

    try:
        if (a=='q'or a=='Q'):
            break
        else:
            print("Invalid data entered. Please enter a number to add or q/Q to quit. ")
            continue
    except ValueError:
        pass
sum= sum_i+ sum_f
print("You have entered ",c," numbers and their sum is: ",sum)

3 Comments

What's with the NameError?
oh yeah - I copied it over from OP's code, but I'll remove it
i got a NameError once when i tried something, so added it to the except. :D

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.