5
\$\begingroup\$

I am a beginner in Python, I want to know if this code can be improved. Is it possible to make it work without the if/else?

number1=int(input('Enter first number: '))
number2=int(input('Enter Second number: '))
operation=input("Enter operation\n[+,-,*,/]")
if operation == '+':
    sum=number1+number2
elif operation == '-':
    sum =number1-number2
elif operation == '*':
    sum =number1*number2
else:
    sum =number1//number2
print(sum)
\$\endgroup\$

migrated from stackoverflow.com Jun 21 '18 at 9:28

This question came from our site for professional and enthusiast programmers.

  • 5
    \$\begingroup\$ An immediate improvement would be not to use sum as a variable name since it shadows a builtin. \$\endgroup\$ – roganjosh Jun 21 '18 at 9:28
  • \$\begingroup\$ All operations except the last (//), I don't have a non-if/else solution for that. At least without resorting to eval, which should be avoided. \$\endgroup\$ – Mast Jun 21 '18 at 9:40
  • 3
    \$\begingroup\$ sum =number1//number2, sure this totally represent a sum. \$\endgroup\$ – Mathias Ettinger Jun 21 '18 at 10:11
12
\$\begingroup\$

If you don't want any if statements then you can do the same with the operator library and a dictionary. This is by using the dict.get method that allows you to have a default value (operator.floordiv) if the value isn't in the dictionary. After getting a valid function from the dictionary, you then just have to call the function.

import operator

operators = {
    '+': operator.add,
    '-': operator.sub,
    '*': operator.mul
}

number1 = int(input('Enter first number: '))
number2 = int(input('Enter Second number: '))
operation = input("Enter operation\n[+,-,*,/]")
print(operators.get(operation, operator.floordiv)(number1, number2))

I would however not assume division if the user enters random data. And so I'd add an if and else. In this case I'd check that the operator is in the operators dictionary, and perform the operation if it is. If it isn't, then I'd tell the user that they entered an invalid operator:

operators = {
    '+': operator.add,
    '-': operator.sub,
    '*': operator.mul,
    '/': operator.floordiv
}

if operation in operators:
    print(operators[operation](number1, number2))
else:
    print('Invalid operator')

You can also make the operator list in the input automatically created from the dictionary too. To create the string '+,-,*,/' you can use ','.join(['+', '-', '*', '/']), to get the array you can then use operators.keys(). Finally you'd have to insert it into the rest of the string, and so I'd use str.format.

operation = input("Enter operation\n[{}]".format(','.join(operators.keys())))

And so tying this all together you could use:

import operator

operators = {
    '+': operator.add,
    '-': operator.sub,
    '*': operator.mul,
    '/': operator.floordiv
}

number1 = int(input('Enter first number: '))
number2 = int(input('Enter Second number: '))
operation = input("Enter operation\n[{}]".format(','.join(operators.keys())))
if operation in operators:
    print(operators[operation](number1, number2))
else:
    print('Invalid operator')
\$\endgroup\$
  • \$\begingroup\$ Adding to the conciseness, and in the spirit of teaching Python, there's also a chance here to use the ternary operator and Python's dynamic typing to change the last four lines to a single line: print(operators[operation](number1, number2) if operator in operations else "Invalid Operator") This is basically equivalent to writing print(operation in operators ? operators[operation](number1, number2) : 'Invalid Operator') in a different language, but only works in a dynamically typed language like Python \$\endgroup\$ – QuantumHoneybees Jun 22 '18 at 13:21
  • \$\begingroup\$ @QuantumHoneybees Honestly, I find it hard to read. And so I personally wouldn't recommend it here. \$\endgroup\$ – Peilonrayz Jun 22 '18 at 13:42
  • \$\begingroup\$ The main goal was to introduce the ternary operator in Python, and so I do agree. Also, following the "zen of python" readability counts and your code is more readable, but I sometimes prefer a one-liner print statement for conciseness because too many if statements can make the code be unreadable \$\endgroup\$ – QuantumHoneybees Jun 22 '18 at 20:33
7
\$\begingroup\$

sum

you use sum as a variable name, shadowing the builtin, which is generally a bad idea

function

Divide the program into functions with their own goal. Here you have following part

  1. get the 2 numbers
  2. get the operation
  3. do the calculation
  4. present the result

Get the numbers

you ask for an input, which you get returned as a str. You convert this to a number with int. If the input is not an integer value, this will crash the program, so you'll need some sort of input validation.

For the input validation, I will borrow a bit from this answer to another question

def ask_number(message='please enter a number', number_types=None):
    if number_types is None:
        number_types = (int, float, complex)
    while True:
        number = input(message)
        for converter in number_types:
            try:
                return converter(number)
            except ValueError:
                pass
        else:
            print('Please enter a valid number')

In this way, you can specify which types are valid, and in which order they should be tried. You can even use custom types if you want.

This will keep asking until you have a valid number, and can be stopped with ctrl+c, which will raise a KeyboardInteruptError

Get the operation

To make it easy for ourselves, we define the default options for operators

DEFAULT_OPERATIONS = {
    '+': operator.add,
    '-': operator.sub,
    '*': operator.mul,
    '//': operator.floordiv,
    '/': operator.truediv,
    '**': operator.pow,
    '^': operator.pow,
}

This way we can call the function without arguments most of the times

def ask_operator(operators=None):
    if operators is None:
        operators = DEFAULT_OPERATIONS

    message = f'Please select an operator from [{','.join(map(str, operators)))}]'
    while True:
        operator = input(message)
        if operator in operators:
            return operator
        else:
            print('Please enter a valid operator')

putting it together

def main():
    operators = DEFAULT_OPERATIONS

    number1 = ask_number('Please enter the first number:')
    number2 = ask_number('Please enter the second number:')
    operator_str = ask_operator(operators)
    operator = operators[operator_str]

    result = operator(number1, number2)

    print(f'{number1} {operator_str} {number2} = {result}')

which you can put behing a if __name__ == '__main__'-guard

if __name__ == '__main__':
    main()
\$\endgroup\$
-3
\$\begingroup\$

You could use the exec function if you wanted, which takes a string formatted as python code and runs the code that the string represents. After the first three lines, just type:

exec('sum = number1' + operation + 'number2')
print(sum)

You would also want to use an if statement to make sure "operation" is actually an operation before running the above lines, though. You don't want your user to type in something crazy and crash the program.

\$\endgroup\$
  • 2
    \$\begingroup\$ "You don't want your user to type in something crazy and crash the program." That's not the only problem either. I can probably whipe the harddrive of my computer by inputting the (exact) wrong operation. Isn't exec just as bloody dangerous as eval? \$\endgroup\$ – Mast Jun 21 '18 at 19:29
  • 3
    \$\begingroup\$ Sorry, but I have to downvote for the suggestion to use exec. That is a firable offense in my book. \$\endgroup\$ – Hosch250 Jun 21 '18 at 19:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.