1
\$\begingroup\$

I am toying around and playing a lot with defining a function. I'm trying to get extremely comfortable with it. The code I have wrote works fairly well, but definitely is not perfect. Also, the function I made called playagain is having some errors. When I type in "Yes" for the input I'm getting a strange TypeError. If you can fix that, please explain to me how, in the simplest way possible.

import sys
OPTIONS = ["Divide", "divide", "Multiply", "multiply", "Add", "add", "Subtract", "subtract"]
def userinput():
 while True:
 try:
 number = int(input("Number: "))
 break
 except ValueError:
 print("NOPE...")
 return number
def operation():
 while True:
 operation = input("Multiply/Divide/Add: ")
 if operation in OPTIONS:
 break
 else:
 print("Not an option.")
 return operation
def playagain():
 while True:
 again = input("Again? Yes/No: ")
 if again == "Yes" or again == "yes":
 break
 elif again == "No" or again == "no":
 sys.exit(0)
 else:
 print("Nope..")
def multiply(x,y):
 z = x * y
 print(z)
def divide(x,y):
 z = x / y
 print(z)
def add(x,y):
 z = x + y
 print(z)
def subtract(x,y):
 z = x - y
 print(z)
while True:
 operation = operation()
 x = userinput()
 y = userinput()
 if operation == "add" or operation == "Add":
 add(x,y)
 elif operation == "divide" or operation == "Divide":
 divide(x,y)
 elif operation == "multiply" or operation == "Multiply":
 multiply(x,y)
 elif operation == "subtract" or operation == "Subtract":
 subtract(x,y)
 playagain()

I tried defining as much functions as possible to make it simpler and easier to fix and debug. Please let me know what you think.

NOTE: I am not making this program to actually be a beneficial program. I am simply using it to help myself with the defining a function portion of Python.

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Sep 15, 2013 at 7:49
\$\endgroup\$
3
  • \$\begingroup\$ possible duplicate of Python Calculator \$\endgroup\$ Commented Sep 15, 2013 at 8:13
  • \$\begingroup\$ @200_success It's not a duplicate, but a follow-up question. The code is not the same, but an already much improved version of the code in the previous question. \$\endgroup\$ Commented Sep 15, 2013 at 8:42
  • 1
    \$\begingroup\$ @tobias_k I recognize and applaud the improvements, but it's still fundamentally the same question, and any answers to this question will be very similar to those of the predecessor. There are also plenty of suggestions in previous answers that have not been incorporated yet. \$\endgroup\$ Commented Sep 15, 2013 at 8:49

3 Answers 3

4
\$\begingroup\$

Of the feedback on your earlier version of this programme, the most obvious thing that you haven't done yet is to use lower() on text inputs so that you only have to compare against lower case options. e.g.

 again = input("Again? Yes/No: ").lower()
 if again == "yes":
 break
 elif again == "no":
 sys.exit(0)

It might be useful to know that the operations you define already exist as methods of numeric variables in Python, called __mul__, __add__, etc., and are also available within the operator module. e.g. operator.add(3, 4) is equivalent to 3 + 4. So you could, for example, do this

import operator
OPTIONS = {
 'divide': operator.truediv,
 'multiply': operator.mul,
 'add': operator.add,
 'subtract': operator.sub
}
def user_input():
 while True:
 try:
 return int(input("Number: "))
 except ValueError:
 print("NOPE...")
def get_operation():
 while True:
 operation = input("Multiply/Divide/Add/Subtract: ").lower()
 try:
 return OPTIONS[operation]
 except KeyError:
 print("Not an option.")
def play_again():
 while True:
 again = input("Again? Yes/No: ").lower()
 if again == "yes":
 return True
 elif again == "no":
 return False
 else:
 print("Nope..")
while True:
 operation = get_operation()
 x = user_input()
 y = user_input()
 print(operation(x, y))
 if not play_again():
 break
answered Sep 15, 2013 at 10:41
\$\endgroup\$
3
  • \$\begingroup\$ Your code didn't work for me, but it's still a very nice answer. I have provided corrections in a separate answer. \$\endgroup\$ Commented Sep 15, 2013 at 11:15
  • \$\begingroup\$ Thanks, I was mixing up Python 2 and 3. I corrected it above to Python 3 as that is what the question uses. \$\endgroup\$ Commented Sep 15, 2013 at 11:31
  • \$\begingroup\$ Thanks @Stuart I appreciate your answer! I will definitely start using the .lower() , I never really knew about it or knew what it did. I will study your code and make some changes. \$\endgroup\$ Commented Sep 15, 2013 at 18:10
1
\$\begingroup\$

Stuart's code is very nicely written, and provides much to a learner, but it didn't work for me. Fixed versions are too long for just a comment, so here they are.

Python 2

The exact version I use: 2.7.3

import operator
OPTIONS = {
 'divide': operator.div,
 'multiply': operator.mul,
 'add': operator.add,
 'subtract': operator.sub
}
def user_input():
 while True:
 try:
 return input("Number: ")
 except ValueError:
 print("NOPE...")
def get_operation():
 while True:
 operation = raw_input("Multiply/Divide/Add/Subtract: ").lower()
 try:
 return OPTIONS[operation]
 except KeyError:
 print("Not an option.")
def play_again():
 while True:
 again = raw_input("Again? Yes/No: ").lower()
 if again == "yes":
 return True
 elif again == "no":
 return False
 else:
 print("Nope..")
while True:
 operation = get_operation()
 x = user_input()
 y = user_input()
 print operation(x, y)
 if not play_again():
 break

In Python 2, input returns an integer, so int(input(...)) is redundant, and inputting string (for operation and going again) fails. The later is fixed by using raw_input.

Python 3

The exact version I use: 3.2.3

import operator
OPTIONS = {
 'divide': operator.truediv,
 'multiply': operator.mul,
 'add': operator.add,
 'subtract': operator.sub
}
def user_input():
 while True:
 try:
 return int(input("Number: "))
 except ValueError:
 print("NOPE...")
def get_operation():
 while True:
 operation = input("Multiply/Divide/Add/Subtract: ").lower()
 try:
 return OPTIONS[operation]
 except KeyError:
 print("Not an option.")
def play_again():
 while True:
 again = input("Again? Yes/No: ").lower()
 if again == "yes":
 return True
 elif again == "no":
 return False
 else:
 print("Nope..")
while True:
 operation = get_operation()
 x = user_input()
 y = user_input()
 print(operation(x, y))
 if not play_again():
 break

The obvious error here was the last print statement: it's a function in Python 3, so print operation(x, y) had to be replaced with print(operation(x, y)).

The less obvious one is operator.div which doesn't exist in Python 3, but was instead replaced by operator.truediv and operator.floordiv. In the spirit of this program, I assumed that the former is what was intended.

answered Sep 15, 2013 at 11:13
\$\endgroup\$
0
1
\$\begingroup\$

[Warning, Ugly Code Ahead...]

I do not quite understand the question, however, I am assuming that you would like to build a calculator application. I have quickly "whipped up" this code. It is compatible with python3, and comes with a graphical user interphase.

Instead of creating that huge function to determine the operator, just use the eval() function instead in a GUI.

As seen in the function Calculate(), I am actually getting the text input from the display screen and just evaluating it. I also error check using a try and except statement.

Calculator with a GUI:

from tkinter import *
from tkinter import ttk
import time
import random
tk = Tk()
canvas = Canvas(tk, height=400, width=300, bg = 'white')
canvas.pack()
tk.title('Calculator')
tk.resizable(False, False)
class Calculator:
 def Title(self):
 title = Label(tk, text = 'Calculator', font='Times, 20')
 title.place(x = 0, y = 10)
 def EntryBar(self):
 self.CalculationBox = Text(tk, height=2, width=27, font='Times, 15', bg = 'gray60')
 self.CalculationBox.place(x = 0, y = 60)
 self.counter = 1
 def DisplayCal(self, num):
 self.CalculationBox.insert(END, num)
 def Calculate(self):
 try:
 answer = eval(self.CalculationBox.get('1.0', END))
 self.CalculationBox.delete("1.0", END)
 #print(answer) #For debugging
 self.CalculationBox.insert(END, answer)
 except Exception:
 self.CalculationBox.delete("1.0", END)
 self.CalculationBox.insert(END, "Error")
c = Calculator()
class Buttons: 
 def Buttons(self):
 self.ZeroBtn = Button(tk, text = '0', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num=0))
 self.ZeroBtn.place(x = 120, y = 360)
 self.OneBtn = Button(tk, text = '1', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num=1))
 self.OneBtn.place(x = 53, y = 320)
 self.TwoBtn = Button(tk, text = '2', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num=2))
 self.TwoBtn.place(x = 120, y = 320)
 self.ThreeBtn = Button(tk, text = '3', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num=3))
 self.ThreeBtn.place(x = 187, y = 320)
 self.FourBtn = Button(tk, text = '4', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num=4))
 self.FourBtn.place(x = 53, y = 280)
 self.FiveBtn = Button(tk, text = '5', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num=5))
 self.FiveBtn.place(x = 120, y = 280)
 self.SixBtn = Button(tk, text = '6', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num=6))
 self.SixBtn.place(x = 187, y = 280)
 self.SevenBtn = Button(tk, text = '7', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num=7))
 self.SevenBtn.place(x = 53, y = 240)
 self.EightBtn = Button(tk, text = '8', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num=8))
 self.EightBtn.place(x = 120, y = 240)
 self.NineBtn = Button(tk, text = '9', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num=9))
 self.NineBtn.place(x = 187, y = 240)
 self.AddBtn = Button(tk, text = '+', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num='+'))
 self.AddBtn.place(x = 53, y = 200)
 self.MultBtn = Button(tk, text = 'x', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num='*'))
 self.MultBtn.place(x = 120, y = 200)
 self.DivBtn = Button(tk, text = '÷', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num='/'))
 self.DivBtn.place(x = 187, y = 200)
 self.SubBtn = Button(tk, text = '-', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.DisplayCal(num='-'))
 self.SubBtn.place(x = 53, y = 160)
 self.EquBtn = Button(tk, text = '=', height=2, width=8, bg = 'gray60', fg = 'white', command = c.Calculate)
 self.EquBtn.place(x = 187, y = 160)
 self.ClsBtn = Button(tk, text='Clear', height=2, width=8, bg = 'gray60', fg = 'white', command = lambda: c.CalculationBox.delete('1.0',END))
 self.ClsBtn.place(x = 120, y = 160)
b = Buttons()
def main():
 c.Title()
 c.EntryBar()
 b.Buttons()
main()
tk.mainloop()
Sᴀᴍ Onᴇᴌᴀ
29.5k16 gold badges45 silver badges201 bronze badges
answered Dec 24, 2017 at 18:53
\$\endgroup\$

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.