# First python program: basic calculator

I want to start learning python for fun and so I could dig into machine learning projects later in the future maybe.

I started off with a small calculator project just to get the hang of the language and the IDE and wanted to get some feedback. I prefer progressing in baby steps and get some useful tips even though this is a really small project. Any comment would be great (regarding the code itself, code standards, etc)

Here's the code:

calculator.core

MULTIPLY_OPERATOR = '*'
DIVIDE_OPERATOR = '/'
SUBTRACTION_OPERATOR = '-'
PLUS_OPERATOR = '+'
INVALID_CALCULATION_CODE = -1

def summation(first_operand, second_operand):
"""
Summing the two operands
:param first_operand: first operand
:param second_operand: second operand
:return: sum of both operands, success indication
"""
return first_operand + second_operand, True

def subtraction(first_operand, second_operand):
"""
subtraction of second operand from the first
:param first_operand: first operand
:param second_operand: second operand
:return: subtraction of second operand from the first, success indication
"""
return first_operand - second_operand, True

def multiply(first_operand, second_operand):
"""
multiply operands
:param first_operand: first operand
:param second_operand: second operand
:return: multiplication of first and second operands, success indication
"""
return first_operand * second_operand, True

def divide(first_operand, second_operand):
"""
divide first operand by the second
:param first_operand: first operand
:param second_operand: second operand
:return: divide result, success indication
"""
if second_operand == 0:
return INVALID_CALCULATION_CODE, False
return first_operand / second_operand, True

SUPPORTED_OPERATORS_DICT = {
"+": summation,
"-": subtraction,
"/": divide,
"*": multiply
}


calculator_console

from calculator_core import *

INVALID_COMMAND_CODE = -1
EXIT_COMMAND = "exit"

def find_operator_index(command):
"""
Returns the index of the operator in the command
:param command: The string command from the user
:return: The index of the operator
"""

for charIndex in range(len(command)):
if command[charIndex] in SUPPORTED_OPERATORS_DICT.keys():
return charIndex

return INVALID_COMMAND_CODE

def print_error_message(code):
"""
prints error message
:param code: error code
:return:
"""

if code == INVALID_COMMAND_CODE:
print "The command you entered is in valid. Please try again.\n"
elif code == INVALID_CALCULATION_CODE:
print "The calculation is in valid. Please try again\n"

def float_try_parse(value):
"""
gets a string and tries to convert it to int
:param value: string to be converted
:return: integer value and success indication
"""
try:
return float(value), True
except ValueError:
return value, False

def take_commands():
"""
Process a command from the user and outputs the result to the console
:return:
"""

while True:
command = raw_input("Please enter a command\n")

# Exit
if command == EXIT_COMMAND:
return

# Processing a computing command
operator_index = find_operator_index(command)

# Invalid operator index
if operator_index == INVALID_COMMAND_CODE:
print_error_message(INVALID_COMMAND_CODE)
continue

# Parsing first operand
first_operand, success = int_try_parse(command[0:operator_index])
if not success:
print_error_message(INVALID_COMMAND_CODE)
continue

# Parsing second operand
second_operand, success = int_try_parse(command[operator_index+1:])
if not success:
print_error_message(INVALID_COMMAND_CODE)
continue

# Executing The command
result, success_indication = SUPPORTED_OPERATORS_DICT[command[operator_index]](first_operand, second_operand)
if not success_indication:
print_error_message(INVALID_CALCULATION_CODE)
else:
print("{}{}".format(result, '\n'))

if __name__ == '__main__':
"""
The main function
"""

take_commands()


calculator_gui

from tkinter import *
from calculator_core import *

fields = 'First Operand', 'Second Operand'

variables = {'curr_operator': "+"}

def float_try_parse(value):
"""
gets a string and tries to convert it to int
:param value: string to be converted
:return: integer value and success indication
"""
try:
return float(value), True
except ValueError:
return value, False

def compute(entries):
"""
Computes the result of the given computation
:param entries: Form entries
:return:
"""
values = []
for entry in entries:

value = entry[1].get()

value, success = float_try_parse(value)

if not success:
return

values.append(value)

result, success = SUPPORTED_OPERATORS_DICT[variables['curr_operator']](values[0], values[1])

if not success:
return

result_label['text'] = result

def makeform(root, fields):
"""
Creating the form fields
:param root: The form root
:param fields: Fields to be created
:return: The created form entries
"""
entries = []
for field in fields:
row = Frame(root)
lab = Label(row, width=15, text=field, anchor='w')
ent = Entry(row)
lab.pack(side=LEFT)
ent.pack(side=RIGHT, expand=YES, fill=X)
entries.append((field, ent))

return entries

def changed(*args):
"""
Tracks changes of the operator
:param args:
:return:
"""
variables['curr_operator'] = s.get()

if __name__ == '__main__':
root = Tk()

ents = makeform(root, fields)

s = StringVar()
s.set('+')
s.trace('w', changed)
om = OptionMenu(root, s, '+', '-', '*', '/')
om.pack()

b1 = Button(root, text='Compute',
command=(lambda e=ents: compute(e)))
b2 = Button(root, text='Quit', command=root.quit)

result_label = Label(root, text="")
result_label.pack()

root.mainloop()

• Is this Python 2 or 3? From the prints it looks like Python 3, but raw_input exists only in Python 2. We have the tags python-2.x and python-3.x if your code only works in one of the two versions (in that case add them in addition to the python tag). – Graipher Mar 2 '19 at 14:14
• Sorry I forgot to add this tag, yes I accidently wrote it in python 2.. In the next program I will use python 3 – user97059 Mar 2 '19 at 14:40

So, your doc strings look fine. I would like to point out few things

1-) In your core class, you are returning True along with the calculated value but you don't make any validations (Except the division function) so it is always True. You could add a validation function (Maybe as a decorator) and validate the given inputs type's (For example there will be an error if you try to sum up a string and integer

2-) (from calculator_core import *) in your calculator_console script is not really a best practice since it could cause namespace collisions, you could just import it like , 'import calculator_core'

3-) In your 'find_operator_index' function you iterate and find the operator's index and after that you use it for slicing. I would rather find the operator itself and split it by the operator in that case and I would use a comprehension. Like

operator = [operator_char for operator_char in command if operator_char in SUPPORTED_OPERATORS_DICT.keys()]


And validate it like;

if len(operator) > 0:
#there is an operator