编写整洁的python之装饰器
一、装饰器使用前
from tkinter import *
from tkinter import filedialog
import tkinter.messagebox
import pandas as pd
import os
import datetime
today = datetime.date.today()
def main():def selectExcelfile():global sfnamesfname = filedialog.askopenfilename(title='选择Excel文件', filetypes=[('Excel', '*.xlsx'), ('All Files', '*')])text1.insert(INSERT, sfname)def closeThisWindow():root.destroy()def clearroot():text1.delete(0,len(sfname))def sqlexcel():global bdhtry:bdh = pd.read_parquet('{}\\df.parquet.gzip'.format(os.getcwd()))bdh['被保险人证件号']=bdh['被保险人证件号'].astype(str)bdh['电话'] = bdh['电话'].astype(str)except:tkinter.messagebox.showinfo('提示', '确保数据源和运行文件在同一路径下。')tkinter.messagebox.showinfo('提示', '匹配数据加载成功')def doProcess():tkinter.messagebox.showinfo('提示', '开始进行被保人身份证匹配。')try:df = pd.read_excel('{}'.format(sfname))df['匹配内容']=df['匹配内容'].astype(str)bdh[bdh['被保险人证件号'].isin(df['匹配内容'].to_list())].to_excel('身份证匹配{}.xlsx'.format(datetime.datetime.now().strftime('%Y%d%m-%H%M%S')),index=False)tkinter.messagebox.showinfo('提示', '被保险人证件号匹配成功')except:tkinter.messagebox.showinfo('提示', '检查是否只选择一个文件路径。\n且列名为匹配内容。')def telephone():tkinter.messagebox.showinfo('提示', '开始进行电话匹配。')try:df = pd.read_excel('{}'.format(sfname))df['匹配内容']=df['匹配内容'].astype(str)bdh[bdh['电话'].isin(df['匹配内容'].to_list())].to_excel('电话匹配{}.xlsx'.format(datetime.datetime.now().strftime('%Y%d%m-%H%M%S')),index=False)tkinter.messagebox.showinfo('提示', '电话匹配成功')except:tkinter.messagebox.showinfo('提示', '检查是否只选择一个文件路径。\n且列名为匹配内容。')def tbname():tkinter.messagebox.showinfo('提示', '开始进行投保人匹配。')try:df = pd.read_excel('{}'.format(sfname))df['匹配内容']=df['匹配内容'].astype(str)print(df['匹配内容'].to_list())bdh[bdh['付款人'].isin(df['匹配内容'].to_list())].to_excel('投保人匹配{}.xlsx'.format(datetime.datetime.now().strftime('%Y%d%m-%H%M%S')),index=False)tkinter.messagebox.showinfo('提示', '投保人成功')except:tkinter.messagebox.showinfo('提示', '检查是否只选择一个文件路径。\n且列名为匹配内容。')# 初始化root = Tk()# 设置窗体标题root.title('2023年度参保匹配系统')# 设置窗口大小和位置root.geometry('500x300+570+200')label1 = Label(root, text='请选择匹配文件:')label2 = Label(root, text='请选择匹配方式')label3 = Label(root, text='匹配前请先加载数据:')label4 = Label(root, text='再次选择文件请清空路径:',fg="red",font=10)text1 = Entry(root, bg='white', width=35)button1 = Button(root, text='浏览', width=8, command=selectExcelfile)button2 = Button(root, text='被保险人身份证', width=16, command=doProcess)button3 = Button(root, text='电话', width=8, command=telephone)button4 = Button(root, text='投保人', width=8, command=tbname)button5 = Button(root, text='退出', width=8, command=closeThisWindow)# 字体颜色button6 = Button(root, text='加载数据', width=8, command=sqlexcel,fg = "red")button7 = Button(root, text='清空', width=8, command=clearroot,bg="red")label1.pack()label2.pack()label3.pack()text1.pack()button1.pack()button2.pack()button3.pack()button7.pack()label4.pack()label1.place(x=20, y=30)text1.place(x=120, y=30)button1.place(x=390, y=26)label3.place(x=100, y=70)button6.place(x=250, y=66)label2.place(x=200, y=100)button2.place(x=30, y=140)button3.place(x=180, y=140)button4.place(x=280, y=140)button5.place(x=380, y=140)label4.place(x=20,y=200)button7.place(x=300,y=200)root.mainloop()if __name__ == "__main__":main()
以上可以看到很多函数中try except 重复出现,用装饰器可以减少重复代码。
二、装饰器使用后
from tkinter import *
from tkinter import filedialog
import tkinter.messagebox
import pandas as pd
import os
import datetime
today = datetime.date.today()
def main():def selectExcelfile():global sfnamesfname = filedialog.askopenfilename(title='选择Excel文件', filetypes=[('Excel', '*.xlsx'), ('All Files', '*')])text1.insert(INSERT, sfname)def handle_bdh_not_defined(error_msg):def decorator(func):def wrapper(*args, **kwargs):try:return func(*args, **kwargs)except Exception as e:if isinstance(e, NameError) and "name 'bdh' is not defined" in str(e):tkinter.messagebox.showinfo('提示', '未找到匹配数据源,请先点击【加载数据】按钮。')else:tkinter.messagebox.showinfo('提示', error_msg)return wrapperreturn decoratordef closeThisWindow():root.destroy()def clearroot():text1.delete(0,len(sfname))def sqlexcel():global bdhtry:bdh = pd.read_parquet('{}\\df.parquet.gzip'.format(os.getcwd()))bdh['被保险人证件号']=bdh['被保险人证件号'].astype(str)bdh['电话'] = bdh['电话'].astype(str)except:tkinter.messagebox.showinfo('提示', '确保数据源和运行文件在同一路径下。')tkinter.messagebox.showinfo('提示', '匹配数据加载成功')@handle_bdh_not_defined('检查是否只选择一个文件路径。\n且列名为匹配内容。')def doProcess():tkinter.messagebox.showinfo('提示', '开始进行被保人身份证匹配。')df = pd.read_excel('{}'.format(sfname))df['匹配内容'] = df['匹配内容'].astype(str)bdh[bdh['被保险人证件号'].isin(df['匹配内容'].to_list())].to_excel('身份证匹配{}.xlsx'.format(datetime.datetime.now().strftime('%Y%d%m-%H%M%S')), index=False)tkinter.messagebox.showinfo('提示', '被保险人证件号匹配成功')@handle_bdh_not_defined('检查是否只选择一个文件路径。\n且列名为匹配内容。')def telephone():tkinter.messagebox.showinfo('提示', '开始进行电话匹配。')df = pd.read_excel('{}'.format(sfname))df['匹配内容']=df['匹配内容'].astype(str)bdh[bdh['电话'].isin(df['匹配内容'].to_list())].to_excel('电话匹配{}.xlsx'.format(datetime.datetime.now().strftime('%Y%d%m-%H%M%S')),index=False)tkinter.messagebox.showinfo('提示', '电话匹配成功')@handle_bdh_not_defined('检查是否只选择一个文件路径。\n且列名为匹配内容。')def tbname():tkinter.messagebox.showinfo('提示', '开始进行投保人匹配。')df = pd.read_excel('{}'.format(sfname))df['匹配内容']=df['匹配内容'].astype(str)bdh[bdh['付款人'].isin(df['匹配内容'].to_list())].to_excel('投保人匹配{}.xlsx'.format(datetime.datetime.now().strftime('%Y%d%m-%H%M%S')),index=False)tkinter.messagebox.showinfo('提示', '投保人成功')@handle_bdh_not_defined('检查是否只选择一个文件路径。\n且列名为匹配内容。')def bbxname():tkinter.messagebox.showinfo('提示', '开始进行被保险人匹配。')df = pd.read_excel('{}'.format(sfname))df['匹配内容']=df['匹配内容'].astype(str)bdh[bdh['被保险人'].isin(df['匹配内容'].to_list())].to_excel('被保险人匹配{}.xlsx'.format(datetime.datetime.now().strftime('%Y%d%m-%H%M%S')),index=False)tkinter.messagebox.showinfo('提示', '被保险人成功')root = Tk()# 设置窗体标题root.title('2025年度参保匹配系统')# 设置窗口大小和位置root.geometry('500x300+570+200')label1 = Label(root, text='请选择匹配文件:')label2 = Label(root, text='请选择匹配方式')label3 = Label(root, text='匹配前请先加载数据:')label4 = Label(root, text='再次选择文件请清空路径:',fg="red",font=10)text1 = Entry(root, bg='white', width=35)button1 = Button(root, text='浏览', width=8, command=selectExcelfile)button2 = Button(root, text='被保险人身份证', width=16, command=doProcess)button3 = Button(root, text='电话', width=8, command=telephone)button4 = Button(root, text='投保人', width=8, command=tbname)button8 = Button(root, text='被保险人', width=8, command=bbxname)button5 = Button(root, text='退出', width=8, command=closeThisWindow)# 字体颜色button6 = Button(root, text='加载数据', width=8, command=sqlexcel,fg = "red")button7 = Button(root, text='清空', width=8, command=clearroot,bg="red")label1.pack()label2.pack()label3.pack()text1.pack()button1.pack()button2.pack()button3.pack()button8.pack()button7.pack()label4.pack()label1.place(x=20, y=30)text1.place(x=120, y=30)button1.place(x=390, y=26)label3.place(x=100, y=70)button6.place(x=250, y=66)label2.place(x=200, y=100)button2.place(x=30, y=140)button3.place(x=180, y=140)button4.place(x=280, y=140)button5.place(x=380, y=200)button8.place(x=410, y=140)label4.place(x=20,y=200)button7.place(x=300,y=200)root.mainloop()
if __name__ == "__main__":main()
1.不传参数
def handle_bdh_not_defined(func):def wrapper(*args, **kwargs):try:return func(*args, **kwargs)except Exception as e:if isinstance(e, NameError) and "name 'bdh' is not defined" in str(e):tkinter.messagebox.showinfo('提示', '未找到匹配数据源,请先点击【加载数据】按钮。')else:tkinter.messagebox.showinfo('提示', '检查是否只选择一个文件路径。\n且列名为匹配内容。')return wrapper
- 传参数
def handle_bdh_not_defined(error_msg):def decorator(func):def wrapper(*args, **kwargs):try:return func(*args, **kwargs)except Exception as e:if isinstance(e, NameError) and "name 'bdh' is not defined" in str(e):tkinter.messagebox.showinfo('提示', '未找到匹配数据源,请先点击【加载数据】按钮。')else:tkinter.messagebox.showinfo('提示', error_msg)return wrapperreturn decorator
3.使用效果
知其所以然,用之可以明显看出代码的简洁以及逻辑更加清晰。