-1

I'm very fresh to Python and am coding a simple text-based calculator that takes choice input and performs a simple arithmetic process depending on the input. My issue arises in this; regardless of whether I input 'Multiply' or 'Divide', the program is always returning to value of the addition function. Any ideas?

def main():
    whichCalc()
    print(finalNum)

def whichCalc():
    choice = input("Please enter one of the following; "
                   "Add, Multiply or Divide: ")
    if choice == 'Add' or 'add' or 'ADD':
        addNum()
    elif choice == 'Multiply' or 'multiply' or 'MULTIPLY':
        multNum()
    elif choice == 'Divide' or 'divide' or 'DIVIDE':
        divNum()
    else:
        print('What?')

def addNum():
    global finalNum
    finalNum = (firstNum + secondNum)
    return finalNum

def multNum():
    global finalNum
    finalNum = (firstNum * secondNum)
    return finalNum

def divNum():
    global finalNum
    finalNum = (firstNum / secondNum)
    return finalNum

firstNum = int(input('Enter the first number: '))
secondNum = int(input('Enter the second number: '))

main()

I've tried removing the 'or' syntax as well as shifting things around, I'm not sure as to why it's diehard on only using the 'addNum' function even when I'm not calling it.

Bill Hileman
  • 2,798
  • 2
  • 17
  • 24
  • Can be simplified as `if choice.lower() == 'add':`. The `or` statement is not working as you’re expecting, and always evaluating to `True`, given the rule of ‘Truthiness’; if you’d like to do further research on the subject. – S3DEV Feb 16 '23 at 20:48
  • Thank you! I don't think I quite fully understand why the 'or' statement isn't working but I will follow up with research. – jf0ssGremlin Feb 16 '23 at 20:53
  • Your statement is parsed as `if (choice == 'Add') or ('add') or ('ADD'):`. The string `'add'` always has a True value, so the first choice is always taken. It has to be written `if choice == 'Add' or choice == 'add' or choice == 'ADD':`., or even `if choice in ('Add','add','ADD'):`, but the `.lower` option is smarter here. – Tim Roberts Feb 16 '23 at 20:56
  • Since you're trying to do a _case-insensitive_ comparison, see https://stackoverflow.com/q/319426/843953 – Pranav Hosangadi Feb 16 '23 at 20:56

3 Answers3

1

i think this will help

def main():
    whichCalc()

def whichCalc():
    choice = input("Please enter one of the following; "
                   "Add, Multiply or Divide: ")
    if choice == 'Add' or choice =='add' or choice =='ADD':
        print(addNum())
    elif choice == 'Multiply' or choice =='multiply' or choice =='MULTIPLY':
        print(multNum())
    elif choice == 'Divide' or choice =='divide' or choice =='DIVIDE':
        print(divNum())
    else:
        print('What?')

def addNum():
    finalNum = (firstNum + secondNum)
    return finalNum

def multNum():
    finalNum = (firstNum * secondNum)
    return finalNum

def divNum():
    finalNum = (firstNum / secondNum)
    return finalNum

firstNum = int(input('Enter the first number: '))
secondNum = int(input('Enter the second number: '))

main()

you do not need global keyword because you are not going to change the value of the global variable

the functions return values then you can put the function inside print() directly

your problem was in this section :

if choice == 'Add' or 'add' or 'ADD':
    print(addNum())
elif choice == 'Multiply' or 'multiply' or 'MULTIPLY':
    print(multNum())
elif choice == 'Divide' or 'divide' or 'DIVIDE':
    print(divNum())
else:
    print('What?')

because you can not say

if thing == value1 or value2 or value3

Pythoner-sh
  • 134
  • 6
  • 1
    Tip: Use `.lower()` and simplify the `if` statements. Or pop the functions into a `dict` and call accordingly. – S3DEV Feb 16 '23 at 20:55
  • yes , you are right, but this thing is advanced he is a new to python. thanks – Pythoner-sh Feb 16 '23 at 21:02
  • The `dict` option, perhaps. But the `.lower()` approach is an excellent education opportunity, providing it’s explained clearly in the answer. – S3DEV Feb 16 '23 at 21:04
1

When using non-booleans in an if statement, python can act a bit strange if you're not used to it. Let's illustrate this with a code example.

For strings, any empty string ("") will evaluate to False, and any non-empty string will evaluate to True.

def is_string_empty(our_string):
    if our_string:
        print(f"No, {our_string} is not empty")
    else:
        print(f"Yes, {our_string} is empty")

is_string_empty("")
is_string_empty("some string")

Now that we understand this, let's look at the syntax error your code example is making. Specifically, let's focus on this line:

   if choice == 'Add' or 'add' or 'ADD':

You have three boolean expressions here. First, choice == 'Add', which will work as you intended; it will evaluate to True if choice is 'Add'. However, your mistake comes from the next two boolean expression: 'add', when evaluated as a boolean, is True, since it's not empty! Same for evaluation 'ADD'; it will always be True. Since those are being or'd with choice == 'Add', this if statement will always evaluate to True, so it will execute addNum() no matter the input!

This statement should be rewritten as:

   if choice == 'Add' or choice == 'add' or choice == 'ADD':

One last tip: instead of having these ors, you can use the lower() method of strings:

   if choice.lower() == 'add':

This will work for add, adD, aDd, Add, aDd, AdD, etc.

0

Non empty strings are evaluated as True while empty strings are Falsy. The or operator calls the __or__ method which returns the first true item. Calling or on a bunch of strings will returns the first non-empty string. The and operator returns the first falsy item in the chain.

Normally all-caps are used to indicate constants in python. Also try not to use global variables unless necessary. For specifying behavior, being the mathematical operator, pass in everything the function needs to operate. Then the function is only specifying behavior and is getting its arguments from the call arguments and not breaking scopes.

Also using a dictionary is good for mapping keys to values. In Python, functions are objects, so they can be passed around. This is why I stored the three supported functions in the dictionary. The operator is then pulled out and the called on the two numbers.

The dict.setdefault(key, value_if_key_is_missing) method is a one time use method for safely looking up a key in a dictionary. If the key is not found, the default is returned. This does not change the dictionary in any way.

A lambda function is a more semi-advanced function that is just a one-liner function. Normally you don't want to store lambda functions because that can introduce unexpected errors, but ours are okay.

OPS = {'ADD': lambda x, y: x + y,
       'MULTIPLY': lambda x, y: x * y,
       'DIVIDE': lambda x, y: x / y}


def which_calc(x, y, operator):
    default_response = lambda *_: print('What?')
    operator = OPS.setdefault(operator.upper(), default_rsponse)
    return operator(x, y)


def main():
    x = int(input('Enter the first number: '))
    print(x)

    y = int(input('Enter the second number: '))
    print(y)

    choice = input("Please enter one of the following; "
                   "Add, Multiply or Divide: ")
    print(which_calc(x, y, choice))
main()