20231213 实验四《Python程序设计》实验报告
20231213 2024-2025-2 《Python程序设计》实验四报告
课程:《Python程序设计》
班级: 2312
姓名: 蔡明辉
学号:20231213
实验教师:王志强
实验日期:2025年5月14日
必修/选修: 公选课
实验内容
设计一个编码工具箱,集成日常专业知识学习时所用到的功能。
主要包括:
- 各种编码格式的文字编码和解码
- 哈希函数的计算
- 生成大素数、生成随机数
- 对大数进行因子分解
使用tkinter库设计图形化界面
改进方向
考虑拓展方向:
在编码和解码功能部分增加导入和导出文件的功能
增加自动推测可能的编码解码格式,简化操作步骤
在哈希函数部分增加导入文件的功能,方便计算各种文件的哈希值
在大数功能可以增加公钥密码相关的功能,比如生成公私钥对的功能
在编码和解码设计好的接口基础上,进一步实现各种密码加密算法
在生成随机数的功能中,在实际环境中需要生成的大素数超过1024位,此时应当使用判断大数素性的其它计算方法。
设计过程
版本迭代情况
实现基本布局框架
完成分功能模块设计
添加异常处理和输入验证
优化UI布局和交互体验
添加多线程和超时机制
增加公钥密码RSA的密钥生成与加密解密
窗口设计
选择ttk主题控件提升美观度
使用ScrolledText处理长文本输出
使用tkinter.TK()生成窗口,采用响应式布局适应窗口缩放
采用Notebook多标签页布局,方便区分三个功能区
使用frame设计选择框架,进行分组管理
点击查看代码
class codehelper:
def __init__(self, root):
self.root = root
self.root.title("lumiere的编码工具箱")
self.setup_ui()
self.executor = ThreadPoolExecutor(max_workers=1)
self.active_task = None
def setup_ui(self):
style = ttk.Style()
style.configure('TButton', font=('None', 12), padding=6)
style.configure('TLabel', font=('None', 12))
style.configure('TEntry', font=('None', 12))
style.configure('TCombobox', font=('None', 12))
self.notebook = ttk.Notebook(self.root)
self.notebook.pack(fill='both', expand=True, padx=10, pady=10)
#
self.encoding_system()
self.hash_system()
self.math_number_system()
self.exit()
功能分区
下面设计程序的主体框架
主要实现三个功能分区的细节布局
点击查看代码
def encoding_system(self):
tab = ttk.Frame(self.notebook)
self.notebook.add(tab, text="编码工具")
encoding_frame = ttk.LabelFrame(tab, text="编码/解码")
encoding_frame.grid(row=0, column=0, padx=10, pady=5, sticky="nsew")#
ttk.Label(encoding_frame, text="输入文本:").grid(row=0, column=0, sticky="w")
self.input_text = scrolledtext.ScrolledText(encoding_frame, width=50, height=5, font=('None', 12))
self.input_text.grid(row=1, column=0, columnspan=3, pady=5)
ttk.Label(encoding_frame, text="编码类型:").grid(row=2, column=0, sticky="w")
self.encoding_var = tk.StringVar()
encodings = ['utf-8', 'utf-16', 'gbk', 'gb2312','待开发']#
self.encoding_menu = ttk.Combobox(encoding_frame, textvariable=self.encoding_var, values=encodings)
self.encoding_menu.grid(row=2, column=1, pady=5)
ttk.Label(encoding_frame, text="操作:").grid(row=3, column=0, sticky="w")
self.operation_var = tk.StringVar()
ttk.Radiobutton(encoding_frame, text="编码", variable=self.operation_var, value="encode").grid(row=3, column=1)
ttk.Radiobutton(encoding_frame, text="解码", variable=self.operation_var, value="decode").grid(row=3, column=2)
'''
由于方框选项选中后暂时无法实现高亮提示
故此处将编码和解码的操作用圆点选项实现
'''
ttk.Button(encoding_frame, text="执行转换", command=self.encode_and_decode).grid(row=4, column=0, columnspan=3, pady=10)
ttk.Label(encoding_frame, text="输出结果:").grid(row=5, column=0, sticky="w")
self.output_text = scrolledtext.ScrolledText(encoding_frame, width=50, height=5, font=('None', 12))
self.output_text.grid(row=6, column=0, columnspan=3, pady=5)
def hash_system(self):
tab = ttk.Frame(self.notebook)
self.notebook.add(tab, text="哈希函数")
hash_frame = ttk.LabelFrame(tab, text="哈希计算")
hash_frame.pack(padx=10, pady=5, fill='both', expand=True)
ttk.Label(hash_frame, text="输入文本:").pack(anchor="w")
self.hash_input = scrolledtext.ScrolledText(hash_frame, height=4, font=('None', 12))
self.hash_input.pack(fill='x', pady=5)
ttk.Label(hash_frame, text="哈希算法:").pack(anchor="w")
self.hash_type = ttk.Combobox(hash_frame, values=['md5', 'sha1', 'sha256'])
self.hash_type.pack(fill='x', pady=5)
self.hash_type.set('md5')
ttk.Button(hash_frame, text="计算哈希值", command=self.calculate_hash).pack(pady=10)
ttk.Label(hash_frame, text="计算结果:").pack(anchor="w")
self.hash_output = ttk.Entry(hash_frame, font=('None', 12))
self.hash_output.pack(fill='x', pady=5)
def math_number_system(self):
tab = ttk.Frame(self.notebook)
self.notebook.add(tab, text="数字工具")
rand_frame = ttk.LabelFrame(tab, text="随机数生成")
rand_frame.grid(row=0, column=0, padx=10, pady=5, sticky="nsew")
ttk.Label(rand_frame, text="二进制最大位数:").grid(row=0, column=0)
self.rand_input = ttk.Entry(rand_frame)
self.rand_input.grid(row=0, column=1)
ttk.Button(rand_frame, text="生成随机数", command=self.generate_random).grid(row=0, column=2)
ttk.Button(rand_frame, text="生成大素数", command=self.generate_prime).grid(row=0, column=3)
self.rand_output = scrolledtext.ScrolledText(rand_frame, height=4, font=('None', 12))
self.rand_output.grid(row=1, column=0, columnspan=4, sticky="ew")
factor_frame = ttk.LabelFrame(tab, text="因数分解")
factor_frame.grid(row=1, column=0, padx=10, pady=5, sticky="nsew")
ttk.Label(factor_frame, text="输入数字:").grid(row=0, column=0)
self.factor_input = ttk.Entry(factor_frame)
self.factor_input.grid(row=0, column=1)
ttk.Button(factor_frame, text="分解因数", command=self.factor_div).grid(row=0, column=2)
self.factor_output = scrolledtext.ScrolledText(factor_frame, height=4, font=('None', 12))
self.factor_output.grid(row=1, column=0, columnspan=3, sticky="ew")
tab.columnconfigure(0, weight=1)
tab.rowconfigure(0, weight=1)
tab.rowconfigure(1, weight=1)
def exit(self):
exit_frame = ttk.Frame(self.root)
exit_frame.pack(pady=10)
ttk.Button(exit_frame, text="退出程序", command=self.root.quit, style='danger.TButton').pack()
功能实现
对程序主体调用的功能进行具体实现
直接调用hashlib库中的函数,实现哈希函数的计算
调用random库,实现生成随机数
messagebox._show设置弹窗,在计算超过10秒后提示运算超时,并终止运算
关于超时检测,使用线程池执行耗时任务,独立线程
点击查看代码
self.executor = ThreadPoolExecutor(max_workers=1)
future = self.executor.submit(trial_division, n)
self.active_task = future
def check_result():
if future.done():
# 更新UI
else:
if time.time() - start_time > 10:
future.cancel()
# 显示超时提示
具体功能
点击查看代码
def encode_and_decode(self):
try:
text = self.input_text.get("1.0", "end").strip()
encoding = self.encoding_var.get()
operation = self.operation_var.get()
if operation == "encode":
encoded = text.encode(encoding)
hex_result = encoded.hex()
bin_result = bin(int.from_bytes(encoded, byteorder='big'))[2:]
result = f"十六进制: {hex_result}\n二进制: {bin_result}"
else:
if all(c in "0123456789abcdefABCDEF" for c in text):
decoded = bytes.fromhex(text).decode(encoding)
else:
bytes(int(text[i:i+8], 2) for i in range(0, len(text), 8)).decode(encoding)
result = f"解码结果: {decoded}"
self.output_text.delete("1.0", "end")
self.output_text.insert("1.0", result)
except Exception as e:
messagebox.showerror("错误", f"转换失败: {str(e)}")
def calculate_hash(self):
text = self.hash_input.get("1.0", "end").strip().encode()
algorithm = self.hash_type.get()
hash_func = {'md5': hashlib.md5,'sha1': hashlib.sha1,'sha256': hashlib.sha256}[algorithm]
self.hash_output.delete(0, "end")
self.hash_output.insert(0, hash_func(text).hexdigest())
def generate_random(self):
try:
bits = int(self.rand_input.get())
number = random.getrandbits(bits)
self.rand_output.delete("1.0", "end")
self.rand_output.insert("1.0", str(number))
except:
messagebox.showerror("错误", "请输入有效的位数")
#
def generate_prime(self):
"""
由于埃氏筛不适用于本场景
更换为密码学的概率性算法
Miller-Rabin素性测试
时间限制,区测试次数为5
"""
def is_prime(n, k=5):
if n <= 1:
return False
for p in [2,3,5,7,11,13,17,19,23,29]:
if n % p == 0:
return n == p
d = n - 1
s = 0
while d % 2 == 0:
d //= 2
s += 1
for _ in range(k):
a = random.randint(2, min(n-2, 1<<20))
x = pow(a, d, n)
if x == 1 or x == n-1:
continue
for __ in range(s-1):
x = pow(x, 2, n)
if x == n-1:
break
else:
return False
return True
try:
bits = int(self.rand_input.get())
while True:
p = random.getrandbits(bits) | (1 << (bits-1)) | 1
if is_prime(p):
self.rand_output.delete("1.0", "end")
self.rand_output.insert("1.0", str(p))
break
except:
messagebox.showerror("错误", "请输入有效的位数")
def factor_div(self):
"""
分解因子
"""
def trial_division(n):
factors = []
while n % 2 == 0:
factors.append(2)
n //= 2
i = 3
max_factor = isqrt(n) + 1
while i <= max_factor and n > 1:
while n % i == 0:
factors.append(i)
n //= i
max_factor = isqrt(n) + 1
i += 2
if n > 1:
factors.append(n)
return factors
try:
n = int(self.factor_input.get())
start_time = time.time()
future = self.executor.submit(trial_division, n)
self.active_task = future
def check_result():
if future.done():
try:
factors = future.result()
if len(factors) == 1:
result = f"{n} 是素数"
else:
result = " × ".join(map(str, factors))
self.factor_output.delete("1.0", "end")
self.factor_output.insert("1.0", result)
except Exception as e:
messagebox.showerror("错误", str(e))
else:
"""
为避免超出能力的因子分解计算
设定最大运算时间为10秒
据测试可以完成70位二进制非素数的分解
"""
if time.time() - start_time > 10:
future.cancel()
messagebox.showwarning("超时", "运算超时,已终止")
else:
self.root.after(500, check_result)
check_result()
except ValueError:
messagebox.showerror("错误", "请输入有效整数")
主函数
由此已完成所有功能的实现,下面运行主函数
点击查看代码
root = tk.Tk()
root.geometry("800x600")
app = codehelper(root)
root.mainloop()
更新RSA功能
补充增加RSA的密钥生成与加密解密
点击查看代码
def create_rsa_tab(self):
tab = ttk.Frame(self.notebook)
self.notebook.add(tab, text="RSA密码系统")
key_frame = ttk.LabelFrame(tab, text="密钥生成")
key_frame.pack(fill='x', padx=10, pady=5)
ttk.Label(key_frame, text="密钥长度:").grid(row=0, column=0, padx=5, pady=5)
self.rsa_key_size = ttk.Combobox(key_frame, values=[1024, 2048, 4096], width=10)
self.rsa_key_size.grid(row=0, column=1, padx=5, pady=5)
self.rsa_key_size.set(2048)
ttk.Button(key_frame, text="生成密钥对", command=self.generate_rsa_keys).grid(row=0, column=2, padx=5, pady=5)
pub_key_frame = ttk.Frame(key_frame, style='Key.TFrame')
pub_key_frame.grid(row=1, column=0, columnspan=3, padx=5, pady=5, sticky='we')
ttk.Label(pub_key_frame, text="公钥 (n, e):", style='Header.TLabel').pack(anchor='w')
self.rsa_pub_key_text = scrolledtext.ScrolledText(pub_key_frame, height=3, width=80)
self.rsa_pub_key_text.pack(fill='x', padx=5, pady=5)
priv_key_frame = ttk.Frame(key_frame, style='Key.TFrame')
priv_key_frame.grid(row=2, column=0, columnspan=3, padx=5, pady=5, sticky='we')
ttk.Label(priv_key_frame, text="私钥 (n, d):", style='Header.TLabel').pack(anchor='w')
self.rsa_priv_key_text = scrolledtext.ScrolledText(priv_key_frame, height=3, width=80)
self.rsa_priv_key_text.pack(fill='x', padx=5, pady=5)
crypto_frame = ttk.LabelFrame(tab, text="加密/解密")
crypto_frame.pack(fill='x', padx=10, pady=5)
ttk.Label(crypto_frame, text="输入文本:").grid(row=0, column=0, padx=5, pady=5, sticky='w')
self.rsa_input_text = scrolledtext.ScrolledText(crypto_frame, height=4, width=80)
self.rsa_input_text.grid(row=1, column=0, columnspan=3, padx=5, pady=5)
ttk.Button(crypto_frame, text="加密", command=self.rsa_encrypt).grid(row=2, column=0, padx=5, pady=5)
ttk.Button(crypto_frame, text="解密", command=self.rsa_decrypt).grid(row=2, column=1, padx=5, pady=5)
ttk.Label(crypto_frame, text="结果:").grid(row=3, column=0, padx=5, pady=5, sticky='w')
self.rsa_result_text = scrolledtext.ScrolledText(crypto_frame, height=4, width=80)
self.rsa_result_text.grid(row=4, column=0, columnspan=3, padx=5, pady=5)
self.rsa_public_key = None
self.rsa_private_key = None
RSA的具体功能
点击查看代码
import rsa
def generate_rsa_keys(self):
key_size = int(self.rsa_key_size.get())
try:
(pubkey, privkey) = rsa.newkeys(key_size)
self.rsa_public_key = pubkey
self.rsa_private_key = privkey
self.rsa_pub_key_text.delete(1.0, tk.END)
self.rsa_pub_key_text.insert(tk.END, f"n = {pubkey.n}\n")
self.rsa_pub_key_text.insert(tk.END, f"e = {pubkey.e}")
self.rsa_priv_key_text.delete(1.0, tk.END)
self.rsa_priv_key_text.insert(tk.END, f"n = {privkey.n}\n")
self.rsa_priv_key_text.insert(tk.END, f"d = {privkey.d}")
messagebox.showinfo("成功", "RSA密钥对生成成功!")
except Exception as e:
messagebox.showerror("错误", f"生成密钥时出错: {str(e)}")
def rsa_encrypt(self):
if not self.rsa_public_key:
messagebox.showerror("错误", "请先生成RSA公钥")
return
text = self.rsa_input_text.get(1.0, tk.END).strip()
if not text:
messagebox.showerror("错误", "请输入要加密的文本")
return
try:
encrypted = rsa.encrypt(text.encode('utf-8'), self.rsa_public_key)
# (十六进制)
self.rsa_result_text.delete(1.0, tk.END)
self.rsa_result_text.insert(tk.END, encrypted.hex())
messagebox.showinfo("成功", "加密完成!")
except Exception as e:
messagebox.showerror("错误", f"加密失败: {str(e)}")
def rsa_decrypt(self):
if not self.rsa_private_key:
messagebox.showerror("错误", "请先生成RSA私钥")
return
text = self.rsa_input_text.get(1.0, tk.END).strip()
if not text:
messagebox.showerror("错误", "请输入要解密的文本")
return
try:
encrypted = bytes.fromhex(text)
decrypted = rsa.decrypt(encrypted, self.rsa_private_key).decode('utf-8')
self.rsa_result_text.delete(1.0, tk.END)
self.rsa_result_text.insert(tk.END, decrypted)
messagebox.showinfo("成功", "解密完成!")
except Exception as e:
messagebox.showerror("错误", f"解密失败: {str(e)}")
代码:
https://gitee.com/cloud-lumiere/2025-python-course/blob/master/lumiere's codehelpher.py
https://gitee.com/cloud-lumiere/2025-python-course/blob/master/lumiere's codehelpher v2.py (增添了RSA功能)
运行结果
程序测试视频:https://mp.weixin.qq.com/s/DLSVCEc9JfXRwGXHhd53XA
编码与解码


哈希函数

生成随机数与分解因子

RSA的加密与解密


课程总结
序列、函数、流程控制、字符串、面相对象、模块、异常处理、文件,等等这些基础内容,感觉自学一周就差不多掌握,可以加快速度
最重要的是平时练,代码量上去当然就不成问题
正则表达式,socket,爬虫、数据库,这些是课上学习收获较大的地方
没有学到GUI、Web等挺可惜的,不过不耽误自学
补充一点,总是缺少面向对象的意识,总是拿写C的习惯只用函数,这是急需改正的
感想
在上本学期python课之前,我已经有过一年python自学经历。去年4月,在学长的建议下,我开始自学python,看的就是《Python编程:从入门到实践》这本书,学习的效果可以说马马虎虎吧,在学习数据结构时,越来越感觉C语言的不方便,于是平时更加喜欢用python。去年报名参加蓝桥杯,报了python B组,寒假只顾着玩了,算法只粗略的学了一遍、也没刷几道题。虽然觉得这次蓝桥杯特别简单,但最后只拿了省二,真是有些离谱了,我在洛谷上测了有80分……明年再战吧。
在做最后的课程大作业时,结合专业知识、结合本学期所学密码学课程内容及实验,结合本学期所学信息论与编码理论、信息安全课程以及学习中遇到的困惑与不便,我最终决定设计一个编码工具箱,集成日常可能用到的编码工具。
通过自己设计的编码工具箱,解决了平时需要到网络上搜索工具的问题,提高了学习效率,并保证了工具的安全可靠与适合自己使用的便利性,有很大可能日后进一步拓展功能。
C语言感觉学了很多,但自己一直都造不出什么像样的东西,一直面对一个黑框框实在是太难受了。寒假前的计算机实习,勉强做了一个看得过去的界面,很可惜还是死的界面。这学期Python课后,我终于决定做一个顺眼的程序界面。最初本来想着用pygame完成,但配置输入法输入没搞会而且布置界面太复杂,成了废案。最后就用了tkinter库来做界面,完成了整个设计。
Python课我学到的最重要的就是:利用知识解决实际问题。不管是解决密码学的编程实验、还是用外部库实现有趣的功能,Python都是趁手的工具。
终身学习,投入实践,共勉。

浙公网安备 33010602011771号