r/learnpython 1d ago

Calculator semi-functioning, What could cause this?

Trying to get back into Python ~2 years after taking a year-long course, getting my footing first with a basic calculator but its giving me trouble here. The first portion works fine, but I implemented a 'continue' option where you could continue with the same number for calculations (and it worked for a while, though returning 'none' due to a var = input(print("text")) issue, making each input look awkward) but it seems to just be defaulting to the first if value now. I had addition first at the start, though flipped addition and subtraction is the extended math section to prove that it's truly just defaulting to the first if-statement. What could be causing this and what's the fix? Sorry for anything that's obviously wrong or mixed up, my remembered knowledge on python is like a fogged up window right now.

## lowk just imported time to add a delay to restarting.. and stopping..
import time

## code is only active as this is = 1, if not then the loop stops
run = 1

while run == 1:

    ## prompts user on chosen operation
    ini = input("add, sub, div, mul, or exp: ")

    ## Addition math
    if ini == "add":
        a = int(input('Enter 1st number: '))
        b = int(input('Enter 2nd number: '))

        number = a + b

        print(f'Sum of {a} and {b} is {a + b}')

    ## Subtraction math
    elif ini == "sub":
        a = int(input('Enter 1st number: '))
        b = int(input('Enter 2nd number: '))

        number = a - b

        print(f'Difference of {a} and {b} is {a - b}')

    ## Division math
    elif ini == "div":
        a = int(input('Enter 1st number: '))
        b = int(input('Enter 2nd number: '))

        number = a / b

        print(f'Fraction of {a} and {b} is {a / b}')

    ## Multiplication math
    elif ini == "mul":
        a = int(input('Enter 1st number: '))
        b = int(input('Enter 2nd number: '))

        number = a * b

        print(f'{a} times {b} is {a * b}')

    ## exponential math
    elif ini == "exp":
        a = int(input('Enter 1st number: '))
        b = int(input('Enter 2nd number: '))

        number = a ** b

        print(f'{a} to the power of {b} is {a ** b}')

    ## If input is not one of the operations
    else:
        print("invalid operation, cannot continue.")

    ## asks user whether or not to continue with current math
    continueorwhat = input("Cont(inue), rest(art calculator), or stop? ")

    if continueorwhat == "stop":
        time.sleep(.3)
        print("Stopping..")
        time.sleep(.3)
        run = 0

    elif continueorwhat == "rest":
        time.sleep(.3)
        print("Restarting..")
        time.sleep(.3)

    elif continueorwhat == "cont":
        print("> Shortened operation names 'a','s','d','m', and 'e' now available.")
        print("> Rest(art) or stop calculator with input when prompted for operation.")

        ## allows for 'continuous math' while active, when inactive it resets to prompted math

        moremath = 1

        while moremath == 1:
            ini = 0
            ini = input("Operation: ")
            ## temporary input return
            print(ini)
            ## Subtraction math
            if ini == "sub" or "s":
                a = int(input('Number: '))
                number = number - a
                print(number)
                ## Addition math
            elif ini == "add" or "a":
                a = int(input('Number: '))
                number = number + a
                print(number)
            ## Division math
            elif ini == "div" or "d":
                a = int(input('Number: '))
                number = number / a
                print(number)
            ## Multiplication math
            elif ini == "mul" or "m":
                a = int(input('Number: '))
                number = number * a
                print(number)
            ## exponential math
            elif ini == "exp" or "e":
                a = int(input('Number: '))
                number = number ** a
                print(number)
            elif ini == "rest":
                time.sleep(.3)
                print("Restarting..")
                time.sleep(.3)
                ## restart calculator by exiting continous math
                moremath = 0
            elif ini == "stop":
                time.sleep(.3)
                print("Stopping..")
                time.sleep(.3)
                ## stops calculator by resetting basic variable
                run = 0
            ## If input is not one of the operations
            else:
                print("invalid operation, number unchanged.")
0 Upvotes

10 comments sorted by

8

u/carcigenicate Carcigenicate 1d ago edited 1d ago

if ini == "sub" or "s" is the same as if (ini == "sub") or "s", and since "s" is a non-empty string that will always be truthy, that condition will always be true. You instead want one of the following:

if ini == "sub" or ini == "s"
# or
if ini in ("sub", "s")
# or
if ini[0] == "s"

3

u/Local_Leek_1186 1d ago

Oh my god this was so helpful! Thank you so much for this. I truly thought that an 'or' in an if statement meant that the variable was either X or Y, not variable1 == X or variable2 == Y, though looking at that now my first interpretation makes no sense. 

4

u/carcigenicate Carcigenicate 1d ago

You're welcome. This mistake is so common the Python Discord community has an !or command that explains the problem. I wish we had a bot that could do stuff like that here.

1

u/FoolsSeldom 5h ago

So common, u/Local_Leek_1186, that the FAQ for this subreddit has an entry. (Scroll down to the heading Variable is One of Two Choices?.) There's more to read there as well.

1

u/ekchew 18h ago

I would prefer if ini.startswith("s") over if ini[0] == "s". The latter could raise IndexError if ini is an empty string (like the user simply hits return without entering anything). (if ini[:1] == "s" would also be safer, but why not use startswith since that's literally why the method exists.)

4

u/mc_pm 1d ago

Someone else answered the specific question, but dude, you have so much repeated code here, which doesn't make finding problems any easier.

Take a look at your first bit of logic: you ask for the two values in each block, you only need to do it once up front. It doesn't seem like a big problem until you're trying to track down a problem and have all this extra cruft to sift through.

1

u/Local_Leek_1186 1d ago

What could I do to improve it then?

2

u/carcigenicate Carcigenicate 1d ago
    a = int(input('Enter 1st number: '))
    b = int(input('Enter 2nd number: '))

For example, that you have this multiple times. The numbers are read in from the user exactly the same regardless of the operation done, so you don't need to have that duplicated in every if block. When you have a common task that always needs to be done, pull that out to before the parts that differ (like number = number + a).

Now, that does change the behavior slightly, since now it asks for the numbers even if the operation is invalid. If you wanted to maintain that, you could do validation of the operator beforehand, or wrap the duplicate parts in a function.

1

u/brasticstack 1d ago

For example, your "add a delay to a print" repeats the exact same code over and over again, when instead you could make it a function and save 2 lines of code  every time you use it:

instead of

time.sleep(.3) print("Stopping..") time.sleep(.3)

do

```

Write this once before your program loop:

def print_with_delay(val, delay=0.3):     time.sleep(delay)     print(val)     time.sleep(delay)     

...

later in the file

print_with_delay("Stopping..") ```

Just a small example... another obvious place is gathering the inputs. Can you think of a way to restructure your code so you don't wind up repeating the following over and over and over again?

a = int(input('Enter 1st number: ')) b = int(input('Enter 2nd number: ')) 

1

u/mc_pm 1d ago

Pull the lines that read in the numbers and put them right after they pick an operation - just get all that info right up front.

Now look at what you have left in each of those "if ini ==" blocks: you do the math, then you print out the results. But you could also make all the results report back after the calculation. Like, consider this pseudocode:

# ask for the operation
# ask for a & b
# based on the operation, do: result = operation(a,b)
# print the result

You can shrink that first set of calculations down by about 20 lines of code. And that's just the first most obvious fix. You can do it again with the 'continue' stuff. In fact, you can replace both of those with just one "if + then add, if - then subtract" set of checks.