基于 Python 的简单计算器系统设计与实现
本文将介绍一个基于 Python 的简单计算器系统,该系统可以进行加、减、乘、除等基本数学运算,并提供了一些额外的功能,如计算器历史记录、结果保存和导入等。本文首先介绍了系统的需求分析和概要设计,然后详细讨论了系统的实现和测试。最后,本文对系统进行了总结和展望。
第一章:绪论
1.1 选题背景和意义
计算器是一种广泛使用的电子设备,可用于进行各种数学运算。随着计算机技术的发展,现在的计算器已经发展成为了一种功能强大、体积小、使用简便的电子设备。特别是在教学、科研和日常生活中,计算器已经成为了必不可少的工具。
本文基于 Python 开发了一个简单计算器系统,旨在提供一种方便、快捷、易于使用的计算器工具,满足人们的计算需求。该系统不仅可以进行基本的数学运算,还提供了一些额外的功能,如计算器历史记录、结果保存和导入等,方便用户进行多次计算和查询。
1.2 计算器系统的需求分析
在设计计算器系统之前,首先需要进行需求分析,明确系统的功能和性能要求。本文的计算器系统要求具有以下功能:
(1)基本数学运算功能:加、减、乘、除等基本数学运算。
(2)科学计算功能:支持常用的科学计算函数,如 sin、cos、tan、log 等。
(3)计算器历史记录:记录用户进行过的计算过程和结果,方便用户进行查询和检索。
(4)结果保存和导入:允许用户将计算结果保存到本地文件,也允许用户从本地文件导入计算结果。
(5)用户友好界面:界面简洁、易于使用,允许用户进行自定义设置。
1.3 计算器系统的概要设计
在进行需求分析之后,需要进行概要设计,明确系统的结构和功能模块。本文的计算器系统采用了 MVC(Model-View-Controller)模式,将系统分为三个部分:模型、视图和控制器。
(1)模型:模型层负责数据的处理和管理,包括用户输入的数据、计算结果和历史记录等。在本文的计算器系统中,模型层采用了面向对象的方式实现,将计算器系统中的各个数据抽象成不同的对象,如数字对象、运算符对象、历史记录对象等。
(2)视图:视图层负责系统的用户界面,将模型层的数据以可视化的方式呈现给用户。在本文的计算器系统中,视图层采用了 tkinter 库实现,提供了一个简洁、美观、易于使用的用户界面。
(3)控制器:控制器层负责系统的逻辑处理,将视图层和模型层进行连接,实现用户界面和数据的交互。在本文的计算器系统中,控制器层采用了 Python 函数实现,将用户输入的数据传递给模型层进行计算,并将计算结果返回给视图层显示。
第二章:系统实现
2.1 系统环境和工具
本文的计算器系统采用 Python 语言进行开发,开发环境为 Windows 10 操作系统。以下是系统开发中所使用的主要工具和库:
(1)Python 3.7.4:Python 是一种高级编程语言,具有易于上手、灵活、可扩展等优点,是本文计算器系统的主要开发语言。
(2)tkinter 库:tkinter 是 Python 自带的 GUI(Graphical User Interface)库,提供了一组用于创建 GUI 应用程序的模块,是本文计算器系统的用户界面实现方式。
(3)pickle 库:pickle 是 Python 自带的序列化和反序列化库,可以将 Python 对象转换为二进制流,是本文计算器系统结果保存和导入的实现方式。
2.2 模型层的实现
模型层负责对用户输入的数据进行处理,并将计算结果返回给控制器层。在本文的计算器系统中,模型层采用了面向对象的方式实现,将计算器系统中的各个数据抽象成不同的对象。
2.2.1 数字对象的实现
数字对象用于保存用户输入的数字,可以进行加、减、乘、除等基本运算。在本文的计算器系统中,数字对象的实现如下:
class Number:
def __init__(self, num):
self.value = num
def __add__(self, other):
return Number(self.value + other.value)
def __sub__(self, other):
return Number(self.value - other.value)
def __mul__(self, other):
return Number(self.value * other.value)
def __truediv__(self, other):
return Number(self.value / other.value)
def __str__(self):
return str(self.value)
在数字对象的实现中,init 方法用于初始化数字对象,add、sub、mul、truediv 方法用于实现数字对象的加、减、乘、除等基本运算,str 方法用于将数字对象转换为字符串。
2.2.2 运算符对象的实现
运算符对象用于保存用户输入的运算符,可以进行优先级比较。在本文的计算器系统中,运算符对象的实现如下:
class Operator:
def __init__(self, op):
self.value = op
def __lt__(self, other):
return self.priority() < other.priority()
def __eq__(self, other):
return self.priority() == other.priority()
def priority(self):
if self.value in ('+', '-'):
return 1
elif self.value in ('*', '/'):
return 2
elif self.value in ('(', ')'):
return 0
else:
return -1
def __str__(self):
return str(self.value)
在运算符对象的实现中,init 方法用于初始化运算符对象,lt、eq 方法用于实现运算符对象的优先级比较,priority 方法用于返回运算符的优先级,str 方法用于将运算符对象转换为字符串。
2.2.3 历史记录对象的实现
历史记录对象用于保存用户进行过的计算过程和结果,可以进行保存和导入。在本文的计算器系统中,历史记录对象的实现如下:
class History:
def __init__(self):
self.history = []
def add(self, expression, result):
self.history.append((expression, result))
def save(self, filename):
with open(filename, 'wb') as f:
pickle.dump(self.history, f)
def load(self, filename):
with open(filename, 'rb') as f:
self.history = pickle.load(f)
def __str__(self):
return '
'.join([f'{expr} = {result}' for expr, result in self.history])
在历史记录对象的实现中,init 方法用于初始化历史记录对象,add 方法用于添加新的计算过程和结果,save 方法用于将历史记录保存到本地文件,load 方法用于从本地文件导入历史记录,str 方法用于将历史记录对象转换为字符串。
2.3 视图层的实现
视图层负责系统的用户界面,将模型层的数据以可视化的方式呈现给用户。在本文的计算器系统中,视图层采用了 tkinter 库实现,提供了一个简洁、美观、易于使用的用户界面。
2.3.1 用户界面的设计
本文的计算器系统的用户界面如下所示:

用户界面由两个部分组成:输入框和按钮。输入框用于显示用户输入的数据和计算结果,按钮用于进行各种操作,如数字输入、运算符输入、计算、清空、保存、导入等。
2.3.2 GUI 程序的实现
本文的计算器系统的 GUI 程序如下所示:
import tkinter as tk
from model import Number, Operator, History
class CalculatorGUI:
def __init__(self):
self.window = tk.Tk()
self.window.title('Calculator')
self.window.geometry('300x300')
self.expression = tk.StringVar()
self.result = tk.StringVar()
self.history = History()
self.create_widgets()
def create_widgets(self):
input_frame = tk.Frame(self.window)
input_frame.pack(side=tk.TOP, padx=10, pady=10)
tk.Entry(input_frame, textvariable=self.expression, width=25).pack(side=tk.LEFT)
tk.Button(input_frame, text='C', width=5, command=self.clear).pack(side=tk.LEFT)
button_frame = tk.Frame(self.window)
button_frame.pack(side=tk.TOP, padx=10, pady=10)
tk.Button(button_frame, text='1', width=5, command=lambda:self.add_digit('1')).grid(row=0, column=0)
tk.Button(button_frame, text='2', width=5, command=lambda:self.add_digit('2')).grid(row=0, column=1)
tk.Button(button_frame, text='3', width=5, command=lambda:self.add_digit('3')).grid(row=0, column=2)
tk.Button(button_frame, text='+', width=5, command=lambda:self.add_operator('+')).grid(row=0, column=3)
tk.Button(button_frame, text='4', width=5, command=lambda:self.add_digit('4')).grid(row=1, column=0)
tk.Button(button_frame, text='5', width=5, command=lambda:self.add_digit('5')).grid(row=1, column=1)
tk.Button(button_frame, text='6', width=5, command=lambda:self.add_digit('6')).grid(row=1, column=2)
tk.Button(button_frame, text='-', width=5, command=lambda:self.add_operator('-')).grid(row=1, column=3)
tk.Button(button_frame, text='7', width=5, command=lambda:self.add_digit('7')).grid(row=2, column=0)
tk.Button(button_frame, text='8', width=5, command=lambda:self.add_digit('8')).grid(row=2, column=1)
tk.Button(button_frame, text='9', width=5, command=lambda:self.add_digit('9')).grid(row=2, column=2)
tk.Button(button_frame, text='*', width=5, command=lambda:self.add_operator('*')).grid(row=2, column=3)
tk.Button(button_frame, text='0', width=5, command=lambda:self.add_digit('0')).grid(row=3, column=0)
tk.Button(button_frame, text='.', width=5, command=lambda:self.add_digit('.')).grid(row=3, column=1)
tk.Button(button_frame, text='(', width=5, command=lambda:self.add_operator('(')).grid(row=3, column=2)
tk.Button(button_frame, text=')', width=5, command=lambda:self.add_operator(')')).grid(row=3, column=3)
tk.Button(button_frame, text='/', width=5, command=lambda:self.add_operator('/')).grid(row=0, column=4)
tk.Button(button_frame, text='%', width=5, command=lambda:self.add_operator('%')).grid(row=1, column=4)
tk.Button(button_frame, text='^', width=5, command=lambda:self.add_operator('^')).grid(row=2, column=4)
tk.Button(button_frame, text='=', width=5, command=self.calculate).grid(row=3, column=4)
result_frame = tk.Frame(self.window)
result_frame.pack(side=tk.TOP, padx=10, pady=10)
tk.Label(result_frame, text='Result:').pack(side=tk.LEFT)
tk.Entry(result_frame, textvariable=self.result, width=25, state='readonly').pack(side=tk.LEFT)
history_frame = tk.Frame(self.window)
history_frame.pack(side=tk.TOP, padx=10, pady=10)
tk.Label(history_frame, text='History:').pack(side=tk.LEFT)
tk.Button(history_frame, text='Save', command=self.save_history).pack(side=tk.LEFT, padx=10)
tk.Button(history_frame, text='Load', command=self.load_history).pack(side=tk.LEFT, padx=10)
self.history_text = tk.Text(history_frame, width=30, height=5, state='readonly')
self.history_text.pack(side=tk.LEFT)
def add_digit(self, digit):
self.expression.set(self.expression.get() + digit)
def add_operator(self, operator):
self.expression.set(self.expression.get() + operator)
def calculate(self):
try:
postfix = self.infix_to_postfix(self.expression.get())
result = self.calculate_postfix(postfix)
self.result.set(result)
self.history.add(self.expression.get(), result)
self.history_text.configure(state='normal')
self.history_text.delete('1.0', tk.END)
self.history_text.insert(tk.END, str(self.history))
self.history_text.configure(state='readonly')
except Exception as e:
self.result.set('Error')
def clear(self):
self.expression.set('')
self.result.set('')
def infix_to_postfix(self, expression):
postfix = []
stack = []
for token in expression:
if token.isdigit() or token == '.':
postfix.append(token)
elif token == '(': stack.append(token) elif token == ')': while stack[-1] != '(': postfix.append(stack.pop()) stack.pop() else: while len(stack) > 0 and stack[-1] != '(' and Operator(token) <= Operator(stack[-1]): postfix.append(stack.pop()) stack.append(token) while len(stack) > 0: postfix.append(stack.pop()) return postfix
def calculate_postfix(self, postfix): stack = [] for token in postfix: if token.isdigit() or token.replace('.', '').isdigit(): stack.append(Number(float(token))) else: b = stack.pop() a = stack.pop() if token == '+': stack.append(a + b) elif token == '-': stack.append(a - b) elif token == '*': stack.append(a * b) elif token == '/': stack.append(a / b) elif token == '%': stack.append(Number(int(a.value) % int(b.value))) elif token == '^': stack.append(Number(a.value ** b.value)) return str(stack[0])
def save_history(self): filename = tk.filedialog.asksaveasfilename() if filename: self.history.save(filename)
def load_history(self): filename = tk.filedialog.askopenfilename() if filename: self.history.load(filename) self.history_text.configure(state='normal') self.history_text.delete('1.0', tk.END) self.history_text.insert(tk.END, str(self.history)) self.history_text.configure(state='readonly')
def run(self): self.window.mainloop()
if __name__ == '__main__': app = CalculatorGUI() app.run
原文地址: https://www.cveoy.top/t/topic/ntKE 著作权归作者所有。请勿转载和采集!