因为pandas.ExcelWriter默认只写入数据、不保留样式,必须用openpyxl引擎在to_excel后、close前手动设置字体、边框、列宽等格式。

用 pandas.ExcelWriter 写入多个 sheet 时,为什么格式全丢了?
因为 ExcelWriter 默认不保留任何单元格样式——它只管数据,不管字体、边框、列宽这些。你直接 df.to_excel(writer, sheet_name="data"),出来的就是纯白板 Excel。
真正起作用的是 openpyxl(或 xlsxwriter)引擎的底层操作能力,但 pandas 自身不暴露样式接口。所以必须在写完数据后,用引擎对象手动操作工作表。
- 必须显式指定
engine="openpyxl"(推荐),xlsxwriter不支持读取/修改已有 sheet 样式 - 写入每个
df后,要调用writer.sheets["sheet_name"]拿到openpyxl.worksheet对象 - 列宽、标题行加粗、自动换行等,都得一行行设,没有“一键套用模板”这种事
openpyxl 修改列宽和标题行加粗的具体写法
写完一个 DataFrame 后,不能立刻关 writer,得先改样式再继续写下一个表。常见操作示例:
with pd.ExcelWriter("report.xlsx", engine="openpyxl") as writer:
df1.to_excel(writer, sheet_name="Summary", index=False)
df2.to_excel(writer, sheet_name="Details", index=False)
<pre class="brush:php;toolbar:false;"># 修改 Summary 表
ws = writer.sheets["Summary"]
for col in ws.columns:
max_length = 0
column = col[0].column_letter
for cell in col:
try:
if len(str(cell.value)) > max_length:
max_length = len(str(cell.value))
except:
pass
adjusted_width = min(max_length + 2, 50) # 防止列宽过大
ws.column_dimensions[column].width = adjusted_width
# 标题行加粗(第1行)
for cell in ws[1]:
cell.font = Font(bold=True)
注意:ws[1] 是第 1 行所有单元格,Font 要从 openpyxl.styles 导入;列宽计算逻辑必须自己写,pandas 不提供 auto_fit_column() 这种方法。
写入多个表时,如何避免覆盖或报错?
常见错误是重复使用同一个 sheet_name,或者在 with 块外操作 writer.sheets —— 此时文件已关闭,对象失效。
-
sheet_name必须唯一,否则后写入的会静默覆盖前一个(无警告) - 所有样式修改必须在
with块内、writer.close()之前完成 - 如果某个表数据为空(
df.empty == True),to_excel仍会创建空 sheet,但writer.sheets["name"]仍可访问,只是没数据行 - 想跳过空表?得提前判断:
if not df.empty: df.to_excel(...)
为什么不用 xlsxwriter 引擎?
它快、内存友好,但只支持“写入”,不支持“读-改-写”。这意味着:
- 无法获取已有 sheet 的
ws对象,writer.sheets是空字典 - 列宽只能靠
set_column()预设,不能根据内容动态算 - 不支持合并单元格、条件格式、图表等进阶功能(
openpyxl支持) - 如果你只需要固定列宽+简单颜色,
xlsxwriter更轻量;但凡要“看数据长度调列宽”或“改标题样式”,就只能切回openpyxl
多表导出带格式这件事,核心矛盾在于:pandas 只负责结构化落表,真正的 Excel 表现力得靠 openpyxl 一格一格去调。别指望封装层替你做完所有事。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











