10
\$\begingroup\$

I have a young friend of mine who is starting to learn Python in school and asked me to give him a little assignment. I am in no way a teacher nor a Python expert, but I accepted.

At first I thought it would be fun to start with a bit of parsing for the operation's input, like:

Enter your operation : 3+3

But it seemed a bit overwhelming for him so we agreed to separate it in three parts (first number, operand and second number).

I did a little correction but I find it clumsy and the point of the exercise is to show him some good practices.

So here is my code:

calculate = True
while calculate:
 try:
 number1 = float(input("Enter the first number : "))
 except ValueError:
 print("Incorrect value")
 exit()
 symbol = input("Enter the operation symbol (+,-,/,*,%) : ")
 try:
 number2 = float(input("Enter the second number : "))
 except ValueError:
 print("Incorrect value")
 exit()
 operande = ["+", "-", "*", "/", "%"]
 resSentence = "Result of operation \"{} {} {}\" is :".format(number1, symbol, number2)
 if symbol not in operande:
 print("Incorrect symbol")
 elif symbol == "+":
 print(resSentence, number1 + number2)
 elif symbol == "-":
 print(resSentence, number1 - number2)
 elif symbol == "*":
 print(resSentence, number1 * number2)
 elif symbol == "/":
 print(resSentence, number1 / number2)
 elif symbol == "%":
 print(resSentence, number1 % number2)
 restart = input("Do you want to do another calcul (Y/n) ? ")
 while restart.lower() != "y" and restart.lower() != "n":
 print(restart.lower(), restart.lower(), restart.lower()=="n")
 restart = input("Please, enter \"y\" to continue or \"n\" to exit the program : ")
 if restart.lower() == "n":
 calculate = False

I would have wanted to do a loop when number1 or number2 is not a valid float until the user enter a valid value, but I did not found a clean way to do it. I would gladly accept advices about this (even though I know this is not a question for this Stack Exchange, a good Pythonic way for doing this would be cool :) ).

Mast
13.8k12 gold badges57 silver badges127 bronze badges
asked Oct 20, 2020 at 19:36
\$\endgroup\$

2 Answers 2

9
\$\begingroup\$

Use more functions

You have a function calculate(), but if you see it does much more than just calculate, this makes your code look unreasonably clunky. But there is a very simply solution, use more functions. What if your main-loop could look like

while True:
 number1,number2,operand = take_input()
 result = calculate(number1,number2,operand)
 print(f"Answer : {numebr1} {operand} {number2} = {result}")
 if input("Do you want to play again? (y/n): ").lower() == 'n':
 break 

This makes it easier to maintain your program.

continue when there is an error

try:
 number1 = float(input("Enter the first number : "))
except ValueError:
 print("Incorrect value")
 exit()

Ask yourself, why would a program terminate if the user enters invalid input? Give him a another chance xD

Maintain consistent indentation

try:
 number2 = float(input("Enter the second number : "))
except ValueError:
 print("Incorrect value")
 exit()

Try to maintain consistent indentation, since you have used 4 spaces earlier, there is no good reason to use 8 later, it might just confuse people who read the code later.

Code logic 1

Let's consider this sample input

Enter the first number : 1
Enter the operation symbol (+,-,/,*,%) : I like python
Enter the second number : 2
Incorrect symbol

Clearly, the symbol is wrong. Why did I have to enter the second number, just to find out I made a mistake while entering the symbol? It should've told me right away that my symbol was incorrect, so I could've corrected it.

Just move the if symbol not in operands statement so it sits right next to the input.

eval

Eval in Python

This would be the biggest improvement in your program, since it converts about 10-15 lines of code, into one.

The eval() function evaluates the specified expression, if the expression is a legal Python statement, it will be executed.

That sounds familiar, aren't we basically evaluating simple expressions?

Using eval, your calculation part would look like

result = eval(f"{number1}{operand}{number2}")

Example, number1 = 5,number2 = 10, operand = '+'

This is what is basically happening

result = eval("5+10")

Final

Here is the code with the improvements

def take_input():
 err_msg = "Invalid input"
 operands = ['+','-','*','/','%']
 try:
 num1 = float(input("Enter number 1: "))
 except Exception:
 print(err_msg)
 return take_input()
 try:
 num2 = float(input("Enter number 2: "))
 except Exception:
 print(err_msg)
 return take_input()
 print("Operands: " + ', '.join(x for x in operands))
 try:
 operand = input("Enter operand: ")
 except Exception:
 print(err_msg)
 return take_input()
 if operand not in operands:
 print(err_msg)
 return take_input()
 return num1,num2,operand
def calculate(num1,num2,operand):
 return eval(f"{num1}{operand}{num2}")
def mainloop():
 while True:
 num1,num2,operand = take_input()
 result = calculate(num1,num2,operand)
 print(f"Answer: {result}")
 if input("Do you want to play again? (y/n): ").lower() == 'n':
 break
mainloop()
answered Oct 21, 2020 at 4:59
\$\endgroup\$
10
  • \$\begingroup\$ I really like the improvements you proposed and how you explained them to me :) As a side question do you think this would be understandable to my young friend (14 y/o) who just started python and only saw if statement in class (he is motivated though since he himself came to me to learn more about coding and so far he seems to really enjoy it). I guess the harder will be to not give him the code but to let him do some search and do trial and error by himself ^^. I will wait untill tonight (I am in France) before accepting an answer but so far, I will accept yours :) \$\endgroup\$ Commented Oct 21, 2020 at 10:49
  • 2
    \$\begingroup\$ Well I'll do my best to explain him as clearly as possible and to let him search by himself :) Wow I would really not have guessed, you have a bright future ahead of you \$\endgroup\$ Commented Oct 21, 2020 at 10:59
  • 1
    \$\begingroup\$ @L.Faros There are plenty of resources to learn python online. This one was extremely useful to me \$\endgroup\$ Commented Oct 21, 2020 at 11:05
  • 1
    \$\begingroup\$ @L.Faros the final code could be thought of as If statements. Basically, all Try/Except is doing is saying (using the first one as an example) "If setting num1 to a float results in a Value error, print the error message and re-run take_input. If there is no error setting num1 to a float, then do that and continue to the next line after except". \$\endgroup\$ Commented Oct 21, 2020 at 18:34
  • \$\begingroup\$ Something I noticed, if the users second input results in an error, they have to restart and put in number 1 again. Perhaps that's by design and is intended, but one alternate would be to just ask for the second number again (via whatever method you like). Same with operand. (Though this is a simple program so it's probably overkill. Just something for OP to consider trying) \$\endgroup\$ Commented Oct 21, 2020 at 18:37
5
\$\begingroup\$

This is an alternative to your code, it is a bit more complex but it is also more readable. I did manage to do the loop thing but it is kind of hard to follow. Sorry.

running = True
# Break Things up into functions each function does one single thing
def calculate(inputOne, operand, inputTwo):
 """
 Calculates inputOne operand and inputTwo
 """
 if operand == "+":
 return inputOne + inputTwo
 elif operand == "-":
 return inputOne - inputTwo
 elif operand == "*":
 return inputOne * inputTwo
 elif operand == "/":
 return inputOne / inputTwo
 elif operand == "%":
 return inputOne % inputTwo
def askInput():
 """
 Asks for a number until a number is given checks if each one is valid
 """
 isValid = [False, False, False] # none of the numbers are validated yet
 number1, symbol, number2 = ["", "", ""]
 
 # Here is a good implementation of the loop, it is kind of complex though
 while True:
 try:
 if not isValid[0]: # Asks for number1 if it is not valid
 number1 = int(input("Enter the first number : "))
 isValid[0] = True
 if not isValid[1]: # This is added functionality because there was a loophole in your program
 symbol = input("Enter the operation symbol (+,-,/,*,%) : ") # use tuples whenever possible
 supportedOperands = ("+", "-", "/", "*", "%")
 if symbol not in supportedOperands:
 raise ValueError
 isValid[1] = True
 if not isValid[2]: # Asks for number2 if it is not valid
 number2 = int(input("Enter the second number : "))
 isValid[2] = True
 break
 
 except ValueError:
 continue # this just restarts the whole thing
 
 return number1, symbol, number2
def continueApp():
 """
 Checks if the input to restart is valid
 """
 restart = input("Do You want to do another calculation (Y/n) ? ").lower()
 while True:
 if restart == "y":
 return True
 elif restart == "n":
 return False
 else:
 restart = input("Please, enter \"y\" to continue or \"n\" to exit the program : ").lower()
while running:
 numberOne, operand, numberTwo = askInput()
 answer = calculate(numberOne, operand, numberTwo)
 resSentence = f"Result of operation {numberOne} {operand} {numberTwo} is : {answer}"
 print(resSentence)
 if continueApp():
 pass
 else:
 running = False
exit()

Tips:

  • Break Things Up into functions:

Functions are just containers for code that can be executed, functions MUST do ONE and only ONE thing more on functions here.

  • Please Try to comment on your code, it makes it easier to read and edit.

This function

def calc():
 x = 1
 y = 12
 return (((x+y)/x)**y)+(3*x+4*y) # Please don't write like this in any case

would be much better with an explanation or what is going on

def calc():
 """
 Accepts: Nothing
 Does: Adds X and Y, then divides it by X to the power of Y
 then it adds it to X multiplied by three and 4 multiplied by Y
 Returns: integer (the result of Does) ^^^^^
 """
 x = 1
 y = 12
 return ((x+y)/x**y)+(3*x+4*y) # Again, please don't write code like this
  • Use f strings (this requires python 3.6 and above)

f strings are used like this

value = "12"
print(f"Number {value} is an example of an f string") 
# Versus
print("Number {} is an example of an f string".format(value))
  • Try to space out your code

Trust me, this makes your code easier to read and understand.

def calc():
 """
 Accepts: Nothing
 Does: Adds X and Y, then divides it by X to the power of Y
 then it adds it to X multiplied by three and 4 multiplied by Y
 Returns: integer (the result of Does) ^^^^^
 """
 x = 1
 y = 12
 ans = (x + y) / (x ** y)
 ans += (3 * x) + (4 * y) # just adds ans to the right side of the operator
 return ans
answered Oct 20, 2020 at 21:54
\$\endgroup\$
5
  • 1
    \$\begingroup\$ The operand could be the key of a dictionary, that leads to \$O(1)\$ search time. \$\endgroup\$ Commented Oct 21, 2020 at 0:37
  • \$\begingroup\$ Well I tried to avoid functions since he is a new learner and the exercise should be more oriented about basics programming skills (conditions, loop...) but tyvm \$\endgroup\$ Commented Oct 21, 2020 at 0:49
  • \$\begingroup\$ Though I like your implementation, I would like to go step by step and avoid using functions since he is young and already have difficulties following a simple script \$\endgroup\$ Commented Oct 21, 2020 at 0:54
  • \$\begingroup\$ This answer doesn't seem to be focused on code review but rather to offer an alternative solution. Would you mind explaining (edit your answer) how is this any better from the OP's code? What did you improve? \$\endgroup\$ Commented Oct 21, 2020 at 6:43
  • \$\begingroup\$ Yeah, sorry, I will fix that. \$\endgroup\$ Commented Oct 21, 2020 at 15:04

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.