4
\$\begingroup\$

I am new to python, I made a calculator but I need to make it calculating unlimited numbers and to shorten the code more, how can I improve it? Any help is appreciated.

while(True):
    print()
    try:
        nums = int(input("How many numbers you want to calculate?\n"))
    # x = float(input("Enter the first number: "))
    # y = float(input("Enter the second number: "))
    # z = float(input("Enter the third number: "))
    # w = float(input("Enter the forth number: "))
    # v = float(input("Enter the fifth number: "))

        if nums == 2:
            x = float(input("Enter the first number: "))
            y = float(input("Enter the second number: "))
            print()
            func = int(input('''What do you want to do?
            1 to add
            2 to subtract
            3 to multiply
            4 to divide
            '''))
            if func == 1:
                print(x+y)
            if func == 2:
                print(x-y)
            if func == 3:
                print(x*y)
            if func == 4:
                print(x/y)
        if nums == 3:
            x = float(input("Enter the first number: "))
            y = float(input("Enter the second number: "))
            z = float(input("Enter the third number: "))
            print()
            func = int(input('''What do you want to do?
            1 to add
            2 to subtract
            3 to multiply
            4 to divide
            '''))
            if func == 1:
                print(x+y+z)
            if func == 2:
                print(x-y-z)
            if func == 3:
                print(x*y*z)
            if func == 4:
                print(x/y/z)
        if nums == 4:
            x = float(input("Enter the first number: "))
            y = float(input("Enter the second number: "))
            z = float(input("Enter the third number: "))
            w = float(input("Enter the forth number: "))
            print()
            func = int(input('''What do you want to do?
            1 to add
            2 to subtract
            3 to multiply
            4 to divide
            '''))
            if func == 1:
                print(x+y+z+w)
            if func == 2:
                print(x-y-z-w)
            if func == 3:
                print(x*y*z*w)
            if func == 4:
                print(x/y/z/w)
        if nums == 5:
            x = float(input("Enter the first number: "))
            y = float(input("Enter the second number: "))
            z = float(input("Enter the third number: "))
            w = float(input("Enter the forth number: "))
            v = float(input("Enter the fifth number: "))
            print()
            func = int(input('''What do you want to do?
            1 to add
            2 to subtract
            3 to multiply
            4 to divide
            '''))
            if func == 1:
                print(x+y+z+w+v)
            if func == 2:
                print(x-y-z-w-v)
            if func == 3:
                print(x*y*z*w*v)
            if func == 4:
                print(x/y/z/w/v)
        if nums > 5:
            print("The calculator handles 5 numbers maximum!")
    except(ZeroDivisionError):
        print("You can never divide by Zero!")
    except(ValueError):
        print("Check your input.")
\$\endgroup\$
  • \$\begingroup\$ are you familiar with for loops? \$\endgroup\$ – Ted Brownlow Aug 10 at 13:21
7
\$\begingroup\$

Loops would be the perfect tool here to reduce duplication; although getting it exactly as you have will be difficult due to you currently spelling out numbers ("first", "second", "third"...). For the sake of simplicity, I'm going to ignore the numeric words, because producing those is non-trivial and a whole project on its own unless you use an existing library.

In their place, I'm going to use a simple function. This can be optimized using a dictionary acting as a case, but I think it's fine as-is besides some minor duplication:

def format_number(n: int) -> str:
    last_digit = str(n)[-1]
    if last_digit == "1":
        return f"{n}st"
    elif last_digit == "2":
        return f"{n}nd"
    elif last_digit == "3":
        return f"{n}rd"
    else:
        return f"{n}th"

>>> format_number(2)
'2nd'
>>> format_number(5)
'5th'
>>> format_number(1)
'1st'

It goes a little bit wonky in the teens ("12nd"), but like I said, it isn't a super straightforward problem, and I don't want to sidetrack the review.


First, you can ask for numbers using a loop, and in the loop, place the entered numbers into a list:

nums = int(input("How many numbers you want to calculate?\n")) 

entered_nums = []
for n in range(nums):
    x = float(input(f"Enter the {format_number(n + 1)} number: "))
    entered_nums.append(x)

When run, I get:

How many numbers you want to calculate?
3
Enter the 1st number: 9
Enter the 2nd number: 8
Enter the 3rd number: 7

And entered_nums now holds [9, 8, 7].

If you're at all familiar with list comprehensions though, you'll notice that that loop can be simplified a bit:

entered_nums = [float(input(f"Enter the {format_number(n + 1)} number: "))
                for n in range(nums)]

And this will have the same effect with a bit less bulk.


Once you have the numbers to do math on, you need to ask for the operation to apply, then apply that operation.

For the first, I'm going to import the operator module because it'll make life much easier. operator.add for example is the same thing as +; only it can be stored as an object.

I'm going to use a dictionary to store the menu code to operator relationship:

from operator import add, sub, mul, truediv
. . .

func = int(input('''What do you want to do?
            1 to add
            2 to subtract
            3 to multiply
            4 to divide
            '''))

code_to_op = {1: add,
              2: sub,
              3: mul,
              4: truediv}

This allows for easily doing math:

>>> code_to_op = {1: add,
                  2: sub,
                  3: mul,
                  4: truediv}

>>> op = code_to_op[3]
>>> op(3, 5)
15

Note though that a bad dictionary lookup will cause an error. code_to_op[5] for example will raise a KeyError. I didn't handle that for simplicity and because you currently aren't handling bad input. It should be dealt with though.


So now once we can get the operator that the user wants, we need to apply it to the numbers they entered. Again, a loop (or something that acts as a loop) is our friend here. We'll need to keep track of the current result of the equation (the "accumulator"), and a loop to do the math:

acc = entered_nums[0]  # The first number they entered will be our starting accumulator
for entered_num in entered_nums[1:]:  # And we'll loop over all the numbers after the first
    acc = op(acc, entered_num)

print(acc)

If the user entered in the numbers 2, 3, and 4, and then entered in 1 for the operator (add), acc would hold 9.0 at the end of that loop.

The acc+loop pattern is incredibly common in programming though. So common in fact that it has its own name: reduce:

from functools import reduce

. . .

result = reduce(op, entered_nums)

reduce here automates the looping for us. It's essentially equivalent to the previous loop that calculated the same value.


After taking that all into consideration, I'm left with:

from operator import add, sub, mul, truediv
from functools import reduce

def format_number(n: int) -> str:
    if n == 1:
        return f"{n}st"
    elif n == 2:
        return f"{n}nd"
    elif n == 3:
        return f"{n}rd"
    else:
        return f"{n}th"

while True:
    try:
        nums = int(input("How many numbers you want to calculate?\n"))

        entered_nums = [float(input(f"Enter the {format_number(n + 1)} number: "))
                        for n in range(nums)]

        code_to_op = {1: add,
                      2: sub,
                      3: mul,
                      4: truediv}

        func = int(input('''What do you want to do?
                    1 to add
                    2 to subtract
                    3 to multiply
                    4 to divide
                    '''))

        op = code_to_op[func]

        acc = entered_nums[0]  # The first number they entered will be our starting accumulator

        for entered_num in entered_nums[1:]:  # And we'll loop over all the numbers after the first
            acc = op(acc, entered_num)

        print(acc, "\n")

    except(ZeroDivisionError):
        print("You can never divide by Zero!")

    except(ValueError):
        print("Check your input.")

And an example run:

How many numbers you want to calculate?
6
Enter the 1st number: >? 9
Enter the 2nd number: >? 8
Enter the 3rd number: >? 7
Enter the 4th number: >? 6
Enter the 5th number: >? 5
Enter the 6th number: >? 4
What do you want to do?
                    1 to add
                    2 to subtract
                    3 to multiply
                    4 to divide
                    >? 1
39.0

There is still a lot that can be mentioned (grouping things into functions, fixing some error handling), but I need to start studying for an exam :)

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ It's actually mostly ununderstandable for a beginner in python... \$\endgroup\$ – LyZeN77 Aug 10 at 21:19
  • 1
    \$\begingroup\$ @LyZeN77 If you are unfamiliar with loops, practice their use then revisit my answer. Loops are fundamental to all of programming, and looping of some form will be required to clean up this code. Attempting to teach their use in general would also be fairly senseless, as many guides already exist on the topic; including in the official documentation. If there are particular points in the code I showed that you'd like clarification on, I can try to edit my answer to improve it. \$\endgroup\$ – Carcigenicate Aug 10 at 21:27
  • \$\begingroup\$ I know about loops, but the confusing part was when you changed the (first, second, third) to (1st, 2nd, 3rd) is there a way to make it unlimited amount of numbers? or even a simpler way? \$\endgroup\$ – LyZeN77 Aug 10 at 21:46
  • 1
    \$\begingroup\$ @LyZeN77 If you wanted to, you could replace the x = float(input(f"Enter the {format_number(n + 1)} number: ")) line with just x = float(input("Enter the next number: ")) and get rid of the function. I only included that bit because you had "first", "second"... in your original output. It's purely stylistic. \$\endgroup\$ – Carcigenicate Aug 10 at 21:49
3
\$\begingroup\$

You can store your numbers in a list after taking them as input as a string separated by spaces, then splitting them into a list using the list.split() function and finally converting each of them to integers.

input_string = input('Enter the numbers separated by space: ')
list_of_numbers = []
for character in input_string.split():
    list_of_numbers.append(int(character))
nums = len(list_of_numbers)

In this case, you have your variable nums, and all the numbers you took as input are in the list list_of_numbers. This can also be written in the following way -

list_of_numbers = [int(number) for number in input('Enter all the numbers you want to calculate: ').split()]
nums = len(list_of_numbers)
| improve this answer | |
\$\endgroup\$

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.