파이썬 실전 프로젝트

계산기 만들기-2 : 함수구현

토픽 파이썬 실전 프로젝트

앞서 만든 계산기에 함수를 추가해서 계산이 가능하도록 하겠습니다.

각 버튼별 함수 만들기

함수는 총 3개입니다. (숫자입력 및 AC버튼(지우기) 처리함수, 사칙연산 처리함수, 이퀄버튼 처리함수)

from tkinter import *
from tkinter import ttk

operation = ''  #연산자 저장 변수
temp_number = 0  #이전값 저장 변수

# 숫자버튼 처리 함수
def button_pressed(value):
    # 입력값이 'AC'일때
    if value=='AC':
        number_entry.delete(0,'end')
        print("AC pressed")
    else: # 그외에 0부터 9까지 숫자일때
        number_entry.insert("end",value)
        print(value,"pressed")

# 사칙연산 처리
def math_button_pressed(value):
    global operation  #함수 바깥의 글로벌 변수사용
    global temp_number
    if not number_entry.get() == '': #기존에 입력한 숫자가 있을때만 연산버튼 인식
        operation = value
        temp_number = int(number_entry.get()) #입력된 숫자를 임시변수로 옮기고,
        number_entry.delete(0,'end')  #입력칸을 비우고, 다음숫자를 입력받을 준비.
        print(temp_number,operation)

# 결과 버튼 처리
def equal_button_pressed():
    global operation
    global temp_number
    #연산자나 숫자가 입력되지 않으면, 실행하지 않음.
    if not (operation =='' and number_entry.get()==''):
        number = int(number_entry.get())
        if operation == '/':
            solution = temp_number/number
        elif operation == '*':
            solution = temp_number*number
        elif operation == '+':
            solution = temp_number+number
        else :
            solution = temp_number-number
        # 계산후, 숫자표시칸을 비우고, 계산결과를 표시.
        number_entry.delete(0,'end')
        number_entry.insert(0,solution)
        print(temp_number,operation,number,"=",solution)
        operation = ''
        temp_number = 0
        
    
root = Tk()
root.title("Calculator")
root.geometry("300x200")

entry_value = StringVar(root, value='')

number_entry = ttk.Entry(root, textvariable = entry_value, width=20)
number_entry.grid(row=0, columnspan=3) 


button7 = ttk.Button(root, text="7", command = lambda:button_pressed('7'))
button7.grid(row=1, column=0)
button8 = ttk.Button(root, text="8", command = lambda:button_pressed('8'))
button8.grid(row=1, column=1)
button9 = ttk.Button(root, text="9", command = lambda:button_pressed('9'))
button9.grid(row=1, column=2)
button_div = ttk.Button(root, text="/", command = lambda:math_button_pressed('/'))
button_div.grid(row=1, column=3)

button4 = ttk.Button(root, text="4", command = lambda:button_pressed('4'))
button4.grid(row=2, column=0)
button5 = ttk.Button(root, text="5", command = lambda:button_pressed('5'))
button5.grid(row=2, column=1)
button6 = ttk.Button(root, text="6", command = lambda:button_pressed('6'))
button6.grid(row=2, column=2)
button_mult = ttk.Button(root, text="*", command = lambda:math_button_pressed('*'))
button_mult.grid(row=2, column=3)

button1 = ttk.Button(root, text="1", command = lambda:button_pressed('1'))
button1.grid(row=3, column=0)
button2 = ttk.Button(root, text="2", command = lambda:button_pressed('2'))
button2.grid(row=3, column=1)
button3 = ttk.Button(root, text="3", command = lambda:button_pressed('3'))
button3.grid(row=3, column=2)
button_add = ttk.Button(root, text="+", command = lambda:math_button_pressed('+'))
button_add.grid(row=3, column=3)

button_ac = ttk.Button(root, text="AC", command = lambda:button_pressed('AC'))
button_ac.grid(row=4, column=0)
button0 = ttk.Button(root, text="0", command = lambda:button_pressed('0'))
button0.grid(row=4, column=1)
button_equal = ttk.Button(root, text="=", command = lambda:equal_button_pressed())
button_equal.grid(row=4, column=2)
button_sub = ttk.Button(root, text="-", command = lambda:math_button_pressed('-'))
button_sub.grid(row=4, column=3)

root.mainloop()

 

 

버그수정 #1 : 연속계산

한번 계산후에, 다른숫자를 입력하면, 기존결과를 지우고, 새로 계산하도록 하겠습니다.

이를 위해서, 결과출력 상태를 저장하는 answer_trigger 변수를 True/False 형태로 boolean 으로 사용하도록 하겠습니다.

from tkinter import *
from tkinter import ttk

operation = ''  
temp_number = 0  
# 결과 출력 상태인지 상태저장.
answer_trigger = False

def button_pressed(value):
    global temp_number
    global answer_trigger
    if value=='AC':
        number_entry.delete(0,'end')
        operation = ''
        #AC버튼 누르면, trigger 변수도 초기화.
        answer_trigger = False
        print("AC pressed")
    else:
        #Trigger가 True이면, Entry 초기화후 새로입력.
        if answer_trigger:
            number_entry.delete(0,"end")
            answer_trigger = False
        number_entry.insert("end",value)
        print(value,"pressed")

def math_button_pressed(value):
    global operation 
    global temp_number
    global answer_trigger
    if not number_entry.get() == '':
        operation = value
        temp_number = int(number_entry.get())
        number_entry.delete(0,'end')
        print(temp_number,operation)

def equal_button_pressed():
    global operation
    global temp_number
    global answer_trigger
    if not (operation =='' and number_entry.get()==''):
        number = int(number_entry.get())
        if operation == '/':
            solution = temp_number/number
        elif operation == '*':
            solution = temp_number*number
        elif operation == '+':
            solution = temp_number+number
        else :
            solution = temp_number-number
        number_entry.delete(0,'end')
        number_entry.insert(0,solution)
        print(temp_number,operation,number,"=",solution)
        operation = ''
        temp_number = 0
        # 계산 완료후, Trigger 변수 True로 변경.
        answer_trigger = True
        
    
root = Tk()
root.title("Calculator")
root.geometry("300x200")

entry_value = StringVar(root, value='')

number_entry = ttk.Entry(root, textvariable = entry_value, width=20)
number_entry.grid(row=0, columnspan=3) 


button7 = ttk.Button(root, text="7", command = lambda:button_pressed('7'))
button7.grid(row=1, column=0)
button8 = ttk.Button(root, text="8", command = lambda:button_pressed('8'))
button8.grid(row=1, column=1)
button9 = ttk.Button(root, text="9", command = lambda:button_pressed('9'))
button9.grid(row=1, column=2)
button_div = ttk.Button(root, text="/", command = lambda:math_button_pressed('/'))
button_div.grid(row=1, column=3)

button4 = ttk.Button(root, text="4", command = lambda:button_pressed('4'))
button4.grid(row=2, column=0)
button5 = ttk.Button(root, text="5", command = lambda:button_pressed('5'))
button5.grid(row=2, column=1)
button6 = ttk.Button(root, text="6", command = lambda:button_pressed('6'))
button6.grid(row=2, column=2)
button_mult = ttk.Button(root, text="*", command = lambda:math_button_pressed('*'))
button_mult.grid(row=2, column=3)

button1 = ttk.Button(root, text="1", command = lambda:button_pressed('1'))
button1.grid(row=3, column=0)
button2 = ttk.Button(root, text="2", command = lambda:button_pressed('2'))
button2.grid(row=3, column=1)
button3 = ttk.Button(root, text="3", command = lambda:button_pressed('3'))
button3.grid(row=3, column=2)
button_add = ttk.Button(root, text="+", command = lambda:math_button_pressed('+'))
button_add.grid(row=3, column=3)

button_ac = ttk.Button(root, text="AC", command = lambda:button_pressed('AC'))
button_ac.grid(row=4, column=0)
button0 = ttk.Button(root, text="0", command = lambda:button_pressed('0'))
button0.grid(row=4, column=1)
button_equal = ttk.Button(root, text="=", command = lambda:equal_button_pressed())
button_equal.grid(row=4, column=2)
button_sub = ttk.Button(root, text="-", command = lambda:math_button_pressed('-'))
button_sub.grid(row=4, column=3)

root.mainloop()

 

버그수정 #2 : 소수점형태의 문자열을 int형으로 변환시 오류. 조건부로 float형으로 변환

나눗셈에서 소수점이 생긴후, 이 숫자를 다시 계산하고자 연산자를 입력하면, 소수점형태의 문자열을 int형 숫자로 바꾸는 과정을 거치게 되는데, 이때 오류가 발생합니다. 이때는, 간단한 float_filter()라는 함수를 만들어서, float형으로 바꿔주도록 하겠습니다.

from tkinter import *
from tkinter import ttk

operation = ''  
temp_number = 0  
answer_trigger = False

def button_pressed(value):
    global temp_number
    global answer_trigger
    if value=='AC':
        number_entry.delete(0,'end')
        operation = ''
        answer_trigger = False
        print("AC pressed")
    else:
        if answer_trigger:
            number_entry.delete(0,"end")
            answer_trigger = False
        number_entry.insert("end",value)
        print(value,"pressed")

# 소수점으로 int형 변환시 에러가 날경우, float형으로 반환.
def float_filter(value):
    try:
        int(value)
        return int(value)
    except ValueError:
        return float(value)

def math_button_pressed(value):
    global operation 
    global temp_number
    global answer_trigger
    if not number_entry.get() == '':
        operation = value
        #float_filter 함수 호출.
        temp_number = float_filter(number_entry.get())
        number_entry.delete(0,'end')
        print(temp_number,operation)

def equal_button_pressed():
    global operation
    global temp_number
    global answer_trigger
    if not (operation =='' and number_entry.get()==''):
        number = int(number_entry.get())
        if operation == '/':
            solution = temp_number/number
        elif operation == '*':
            solution = temp_number*number
        elif operation == '+':
            solution = temp_number+number
        else :
            solution = temp_number-number
        number_entry.delete(0,'end')
        number_entry.insert(0,solution)
        print(temp_number,operation,number,"=",solution)
        operation = ''
        temp_number = 0
        answer_trigger = True
        
    
root = Tk()
root.title("Calculator")
root.geometry("300x200")

entry_value = StringVar(root, value='')

number_entry = ttk.Entry(root, textvariable = entry_value, width=20)
number_entry.grid(row=0, columnspan=3) 


button7 = ttk.Button(root, text="7", command = lambda:button_pressed('7'))
button7.grid(row=1, column=0)
button8 = ttk.Button(root, text="8", command = lambda:button_pressed('8'))
button8.grid(row=1, column=1)
button9 = ttk.Button(root, text="9", command = lambda:button_pressed('9'))
button9.grid(row=1, column=2)
button_div = ttk.Button(root, text="/", command = lambda:math_button_pressed('/'))
button_div.grid(row=1, column=3)

button4 = ttk.Button(root, text="4", command = lambda:button_pressed('4'))
button4.grid(row=2, column=0)
button5 = ttk.Button(root, text="5", command = lambda:button_pressed('5'))
button5.grid(row=2, column=1)
button6 = ttk.Button(root, text="6", command = lambda:button_pressed('6'))
button6.grid(row=2, column=2)
button_mult = ttk.Button(root, text="*", command = lambda:math_button_pressed('*'))
button_mult.grid(row=2, column=3)

button1 = ttk.Button(root, text="1", command = lambda:button_pressed('1'))
button1.grid(row=3, column=0)
button2 = ttk.Button(root, text="2", command = lambda:button_pressed('2'))
button2.grid(row=3, column=1)
button3 = ttk.Button(root, text="3", command = lambda:button_pressed('3'))
button3.grid(row=3, column=2)
button_add = ttk.Button(root, text="+", command = lambda:math_button_pressed('+'))
button_add.grid(row=3, column=3)

button_ac = ttk.Button(root, text="AC", command = lambda:button_pressed('AC'))
button_ac.grid(row=4, column=0)
button0 = ttk.Button(root, text="0", command = lambda:button_pressed('0'))
button0.grid(row=4, column=1)
button_equal = ttk.Button(root, text="=", command = lambda:equal_button_pressed())
button_equal.grid(row=4, column=2)
button_sub = ttk.Button(root, text="-", command = lambda:math_button_pressed('-'))
button_sub.grid(row=4, column=3)

root.mainloop()

 

버그수정 #3 : 결과값 정수형으로 처리.

한번 float형으로 계산이 되기 시작하면, 오류는 앞에서 잡더라도, 2.0 처럼, 정수형으로 표현될수 있는 숫자까지도 모두 flaot형으로 출력이 됩니다. 이때는, int(number)==float(number) 가 true이면, 정수라는 판단하에, 정수로 변경해주도록 하겠습니다.

from tkinter import *
from tkinter import ttk

operation = ''  
temp_number = 0  
answer_trigger = False

def button_pressed(value):
    global temp_number
    global answer_trigger
    if value=='AC':
        number_entry.delete(0,'end')
        operation = ''
        answer_trigger = False
        print("AC pressed")
    else:
        if answer_trigger:
            number_entry.delete(0,"end")
            answer_trigger = False
        number_entry.insert("end",value)
        print(value,"pressed")

def float_filter(value):
    try:
        int(value)
        return int(value)
    except ValueError:
        return float(value)

# 두값이 같으면 정수로 표현가능.==> 정수값으로 반환.
def int_changer(value):
    if int(value) == float(value):
        return int(value)
    else:
        return float(value)

def math_button_pressed(value):
    global operation 
    global temp_number
    global answer_trigger
    if not number_entry.get() == '':
        operation = value
        temp_number = float_filter(number_entry.get())
        number_entry.delete(0,'end')
        print(temp_number,operation)

def equal_button_pressed():
    global operation
    global temp_number
    global answer_trigger
    if not (operation =='' and number_entry.get()==''):
        number = int(number_entry.get())
        if operation == '/':
            solution = temp_number/number
        elif operation == '*':
            solution = temp_number*number
        elif operation == '+':
            solution = temp_number+number
        else :
            solution = temp_number-number
            
        #int_changer() 함수를 한번 거쳐서, 값저장.
        solution = int_changer(solution)
        number_entry.delete(0,'end')
        number_entry.insert(0,solution)
        print(temp_number,operation,number,"=",solution)
        operation = ''
        temp_number = 0
        answer_trigger = True
        
    
root = Tk()
root.title("Calculator")
root.geometry("300x200")

entry_value = StringVar(root, value='')

number_entry = ttk.Entry(root, textvariable = entry_value, width=20)
number_entry.grid(row=0, columnspan=3) 


button7 = ttk.Button(root, text="7", command = lambda:button_pressed('7'))
button7.grid(row=1, column=0)
button8 = ttk.Button(root, text="8", command = lambda:button_pressed('8'))
button8.grid(row=1, column=1)
button9 = ttk.Button(root, text="9", command = lambda:button_pressed('9'))
button9.grid(row=1, column=2)
button_div = ttk.Button(root, text="/", command = lambda:math_button_pressed('/'))
button_div.grid(row=1, column=3)

button4 = ttk.Button(root, text="4", command = lambda:button_pressed('4'))
button4.grid(row=2, column=0)
button5 = ttk.Button(root, text="5", command = lambda:button_pressed('5'))
button5.grid(row=2, column=1)
button6 = ttk.Button(root, text="6", command = lambda:button_pressed('6'))
button6.grid(row=2, column=2)
button_mult = ttk.Button(root, text="*", command = lambda:math_button_pressed('*'))
button_mult.grid(row=2, column=3)

button1 = ttk.Button(root, text="1", command = lambda:button_pressed('1'))
button1.grid(row=3, column=0)
button2 = ttk.Button(root, text="2", command = lambda:button_pressed('2'))
button2.grid(row=3, column=1)
button3 = ttk.Button(root, text="3", command = lambda:button_pressed('3'))
button3.grid(row=3, column=2)
button_add = ttk.Button(root, text="+", command = lambda:math_button_pressed('+'))
button_add.grid(row=3, column=3)

button_ac = ttk.Button(root, text="AC", command = lambda:button_pressed('AC'))
button_ac.grid(row=4, column=0)
button0 = ttk.Button(root, text="0", command = lambda:button_pressed('0'))
button0.grid(row=4, column=1)
button_equal = ttk.Button(root, text="=", command = lambda:equal_button_pressed())
button_equal.grid(row=4, column=2)
button_sub = ttk.Button(root, text="-", command = lambda:math_button_pressed('-'))
button_sub.grid(row=4, column=3)

root.mainloop()

 

여기까지 하면, 기본적인 계산은 문제없이 다 되는것 같습니다. 다음토픽에서는, 키보드로 숫자와 연산자를 입력받도록 코드를 좀 바꿔보도록 하겠습니다.

댓글

댓글 본문
  1. user
    다 잘되는데 '='버튼을 누르면 값이 안나옵니다.
  2. nomadlife
    네 제가 변수를 햇갈렸네요.10번째줄에 temp_number 대신 operation 변수로 바꿔주시면 됩니다. 다시 보니 숨어있는 버그들이 꽤 있는거같네요. 저도 공부도 되고 좋으니 혹시 또 잘못된거 있으면 알려주세요. 글 내용은 조만간 업데이트 해놓도록 하겠습니다.
    대화보기
    • 김진호
      버그 수정 #1 10번 라인에 global temp_number가 아니라 global operation이 들어가야 하는거 아닌가요...?
      아니라면 죄송합니다 제가 자 ㄹ몰라서,,, 다만 button_pressed(value) 함수에 temp_number는 사용되지 않고 오히려 operation의 초기화 코드가 포함된 상태인데 global operation이 없어도 되는건지 궁금합니다..!
      좋은 소스 감사합니다