网站首页 > 博客文章 正文
一、两个问题的出现场景
近日使用pandas和xlwt编写了一段脚本,基于期末成绩数据制作成绩表,打印后分发给每个老师。成绩数据包含上课教师、课序号、学生学号、学生姓名和总分等字段,发给老师的成绩表要求每个班(以课序号区分)的成绩单独排成一个纵列,每页最多3列,每个老师的成绩单独分页。编写脚本如下:
import xlrd
import xlwt
import pandas as pd
import numpy as np
from xpinyin import Pinyin
#############################################################
##每次运行程序需要修改成绩数据和成绩单名称
BASE_FILE='成绩数据.xls'
OUT_FILE='成绩单.xls'
#############################################################
p=Pinyin()
def py(v):
return p.get_pinyin(v,'')
def getWidth(columnWidth):
return round(columnWidth*256+182.8571)
def c(v):
return v.replace('*', '')[:-1]
#读取成绩数据并进行预处理,成绩数据包含SKJS, KXH, XH, XM, 总分等字段。
wb = xlrd.open_workbook(IN_FILE,encoding_override='cp936')
df = pd.read_excel(wb, dtype={'KXH':'string', 'XH':'string'})
df.SKJS=df.SKJS.apply(c) #删除任课教师字段里的*号
df['JSPY']=df.SKJS.apply(py) #添加任课教师拼音字段,方便排序
df['KXHINT']=df.KXH.astype(int) #添加课序号数字字段,方便排序
df.sort_values(['JSPY', 'SKJS', 'KXHINT', 'XH'], inplace=True) #值排序
#新建workbook
book = xlwt.Workbook(encoding='utf-8')
sheet=book.add_sheet('成绩单')
sheet.set_header_str(''.encode()) #设置页眉为空
sheet.set_footer_str('202301 FINAL page &P, &N pages'.encode()) #设置页脚
#设置列宽
cc=[13, 7.71, 4, 2, 13, 7.71, 4, 2, 13, 7.71, 4]
i=0
for c in cc:
sheet.col(i).width=getWidth(c)
i+=1
#设置行高
for i in range(5000):
sheet.row(i).height_mismatch = True
sheet.row(i).height = 18*20 #行高18磅,每页44行。
#设置样式
s1=xlwt.easyxf('font:name 微软雅黑, height 240, bold 1; align: horz center, vert center;') #字号12磅
s2=xlwt.easyxf('font:name 宋体, height 220; align: vert center;') #字号11磅
hs=44 #行高18磅时, 每页行数44
teacher=''
total_cols=0
for k, group in df.groupby(['JSPY', 'SKJS', 'KXHINT', 'KXH']):
if k[1]!=teacher:
teacher=k[1]
if total_cols % 3!=0:
total_cols+=3-total_cols % 3
col_id=total_cols
xh_count=group.XH.count()+1
cols=xh_count // hs if xh_count % hs==0 else xh_count // hs+1 #需要列数
total_cols+=cols
start_row=col_id//3*hs
start_col=(col_id % 3)*3+col_id % 3
sheet.write(start_row, start_col, k[1], style=s1)
sheet.write(start_row, start_col+1, k[3], style=s1)
i=1
for c in group.itertuples():
n=(col_id+i//hs) %3
col_offset=n*3+n
row_offset=start_row+i % hs+(i+col_id %3*hs)//(hs*3)*hs
sheet.write(row_offset, col_offset, c.XH, style=s2)
sheet.write(row_offset, col_offset+1, c.XM, style=s2)
sheet.write(row_offset, col_offset+2, c.总分, style=s2)
i+=1
book.save(OUT_FILE)
脚本运行过程中,遇到问题1(注释设置行高代码的情况下):
折腾很久终于解决这个问题(稍后详述),在Excel中打开成绩单文件时,遇到问题2:
问题1让脚本不能正常运行并生成成绩单.xls文件,问题2更让自己惴惴不安:万一真丢了数据,如何从上万条成绩记录中检查丢了哪些数据?!
下面描述探索和解决这两个问题的过程,一方面便于自己加深认识,另一方面希望他人不要继续踩坑。
二、问题1的探索和解决过程
根据错误提示给出的线索,打开xlwt包的Row.py文件,发现这样一段代码:
def __init__(self, rowx, parent_sheet):
if not (isinstance(rowx, int_types) and 0 <= rowx <= 65535):
raise ValueError("row index was %r, not allowed by .xls format" % rowx)
这段代码说明,如果行索引不是整数,或者行索引大于65535,xlwt就会报错。在图1所示的错误信息中,行索引是44,显然报错不是因为行索引越界引发。那么只能是:xlwt判断当前的行索引不是整数。于是赶紧检查start_row和start_col两个变量的类型,下面的发现很意外:
type(start_row)
<class 'numpy.int64'>
type(start_col)
<class 'numpy.int64'>
编写脚本时,我一直以为start_row和start_col就是整数(<class 'int'>),完全没有想到这两个变量居然是numpy.int64。虽然numpy.int64也是整数类型,但是xlwt有时不能准确理解和处理。那么变量start_row如何变成numpy.int64的呢?我注意到这行代码:
xh_count=group.XH.count()+1
xh_count变量用于保存当前班上学号个数+1,脚本使用该变量计算当前班的成绩需要排成几列。查看xh_count的变量类型,发现就是numpy.int64,从而导致其它相关变量全部成为这个整数类型,这就是错误的根源所在。为了阻断该变量“污染”其它变量,添加一行代码:
xh_count=int(xh_count)
经过测试,xlwt不再报错,问题得到解决。当然还有其它解决办法,原则是使用sheet.write方法时,确保传入的行变量和列变量类型必须是python的int,而不是pandas的numpy.int64。
三、问题2的思考和解决过程
问题2不是在运行脚本生成成绩单文件过程中出现的,使得脚本调试更加困难。最初遇到这个问题时,我怀疑可能是xlwt和python/pandas不兼容引起的,毕竟xlwt包从2018年起就没有更新了。于是我编写了一段验证脚本,没有使用pandas dataframe数据,直接用xlwt生成xls文件。但打开这个文件时Excel没有弹出提示框,说明我的怀疑不成立。由此判断,问题还是出在pandas传入的数据上。经过反复调试,发现如果把dataframe的float数据写入xls文件,Excel打开文件时就可能弹出提示。解决这个问题的办法也很简单:把原代码中的float变量使用str函数或float函数进行强制转换即可。如下列代码所示:
sheet.write(row_offset, col_offset+2, c.总分, style=s2)
修改为
sheet.write(row_offset, col_offset+2, float(c.总分), style=s2)
或者修改为
sheet.write(row_offset, col_offset+2, str(c.总分), style=s2)
四、总结
xlwt配合pandas制作格式化报表过程中,使用sheet.write方法写入数据时,必须保证:
- 行变量和列变量类型必须是python的整数(<class 'int'>),而不是pandas的numpy.int64(<class 'numpy.int64'>);
- 写入值是pandas float32类型时,使用python内置的float函数或str函数进行强制转换,这样保证数据安全写入xls文件。
猜你喜欢
- 2024-10-24 python处理excel文件03:xlwt模块写入excel文件
- 2024-10-24 经验 | Python 读写 Excel 文件第三方库汇总
- 2024-10-24 python实现爬取豆瓣电影Top250(python爬取豆瓣电影的流程)
- 2024-10-24 Python如何操作Excel,xlrd和xlwt类库的使用
- 2024-10-24 如何用Python读写Excel文件?最便捷的3种方式
- 2024-10-24 安全服务日常工作之大量端口状态扫描
- 2024-10-24 Python操作Excel库xlrd与xlwt常用操作详解
- 2024-10-24 Python读写Excel表格,就是这么简单粗暴又好用
- 2024-10-24 Python学习之爬取网页信息(python爬取网页数据步骤)
- 2024-10-24 自动化记账程序1.0(自动化会计记账软件)
你 发表评论:
欢迎- 07-08Google Cloud Platform 加入支持 Docker 的容器引擎
- 07-08日本KDDI与Google Cloud 签署合作备忘录,共探AI未来
- 07-08美国Infoblox与Google Cloud合作推出云原生网络和安全解决方案
- 07-08GoogleCloud为Spanner数据库引入HDD层,将冷存储成本降低80%
- 07-08谷歌推出Cloud Dataproc,缩短集群启动时间
- 07-08Infovista与Google Cloud携手推进射频网络规划革新
- 07-08比利时Odoo与Google Cloud建立增强合作,扩大全球影响力
- 07-08BT 和 Google Cloud 通过 Global Fabric 加速 AI 网络
- 最近发表
-
- Google Cloud Platform 加入支持 Docker 的容器引擎
- 日本KDDI与Google Cloud 签署合作备忘录,共探AI未来
- 美国Infoblox与Google Cloud合作推出云原生网络和安全解决方案
- GoogleCloud为Spanner数据库引入HDD层,将冷存储成本降低80%
- 谷歌推出Cloud Dataproc,缩短集群启动时间
- Infovista与Google Cloud携手推进射频网络规划革新
- 比利时Odoo与Google Cloud建立增强合作,扩大全球影响力
- BT 和 Google Cloud 通过 Global Fabric 加速 AI 网络
- NCSA和Google Cloud合作开发AI驱动的网络防御系统,加强泰国网络空间的安全性
- SAP将在沙特阿拉伯 Google Cloud 上推出BTP服务
- 标签列表
-
- ifneq (61)
- 字符串长度在线 (61)
- googlecloud (64)
- messagesource (56)
- promise.race (63)
- 2019cad序列号和密钥激活码 (62)
- window.performance (66)
- qt删除文件夹 (72)
- mysqlcaching_sha2_password (64)
- ubuntu升级gcc (58)
- nacos启动失败 (64)
- ssh-add (70)
- jwt漏洞 (58)
- macos14下载 (58)
- yarnnode (62)
- abstractqueuedsynchronizer (64)
- source~/.bashrc没有那个文件或目录 (65)
- springboot整合activiti工作流 (70)
- jmeter插件下载 (61)
- 抓包分析 (60)
- idea创建mavenweb项目 (65)
- vue回到顶部 (57)
- qcombobox样式表 (68)
- tomcatundertow (58)
- pastemac (61)
本文暂时没有评论,来添加一个吧(●'◡'●)