使用循环从Excel模板生成多份报表时遇IO及属性错误求助
批量生成月度报表问题解决
错误原因解析
第一个错误:ValueError: I/O operation on closed file.
你在循环外仅加载一次模板文件,第一次调用save()后,openpyxl会自动关闭关联的文件句柄,后续循环再执行保存操作时就会触发文件已关闭的错误。同时,直接修改同一个workbook对象会导致后续报表基于上一次修改后的内容生成,而非原始模板。
第二个错误:AttributeError: 'NoneType' object has no attribute 'save'
你自定义的load_temp_workbook类中,__enter__方法没有返回加载完成的workbook实例,因此with语句中得到的wt是None,调用save()方法自然会报错。
正确实现代码
核心思路:每次循环重新加载原始模板,确保每个报表都基于干净的模板生成;同时简化数据处理逻辑,避免数据匹配错误。
import os from openpyxl import load_workbook import pandas as pd # 设置工作目录 path = r"/Users/xxx/Desktop/xxx" os.chdir(path) # 加载并筛选源数据,一次性完成查询提升效率 df = pd.read_excel("Data.xlsx", sheet_name='Sheet1', header=0) filtered_df = df[df['To_choose'] == "Y"] # 循环生成每个客户的报表 for _, row in filtered_df.iterrows(): # 每次循环重新加载原始模板,避免数据污染和文件句柄问题 workbook = load_workbook('template.xlsx') sheet = workbook['Statement'] # 填充基础信息 sheet['B6'].value = row['client'] sheet['G6'].value = "31/12/2022" # 填充业务数据(替换为模板中对应单元格位置) sheet['XX'].value = row['Net'] # 示例:点击量对应的单元格 sheet['YY'].value = row['Fee'] # 示例:应付费用对应的单元格 # 保存个性化报表 workbook.save(f"Statement as of 31 Dec 2022 of {row['client']}.xlsx")
关键优化点
- 循环内重复加载模板:彻底避免模板被修改后污染后续报表,同时解决文件句柄关闭的问题。
- 一次性筛选数据:用布尔索引替代多次
query操作,提升代码运行效率和可读性。 iterrows()遍历数据:直接获取每行完整数据,避免单独提取列后可能出现的顺序不匹配问题。
内容的提问来源于stack exchange,提问作者beaconho
相关产品推荐
相关产品推荐

