Python Excel合并单元格与取消合并:merge_cells用法详解
用openpyxl的merge_cells合并标题单元格、unmerge_cells取消合并,注意合并后只有左上角保留值,附完整可运行代码。
场景痛点
报表开头常要写一个跨几列的大标题「2026 年 9 月销售报表」,手动在 Excel 里选中 A1:E1 点合并居中,每张表都做一遍很烦。反过来,拿到别人合并过的表想读数据,发现除了左上角其它格子都是空的,没法直接处理。用 openpyxl 合并、拆分都能用代码控制。
用到的库
pip install openpyxl
完整代码
from openpyxl import load_workbook
from openpyxl.styles import Alignment
def demo_merge(file_path: str) -> None:
wb = load_workbook(file_path)
ws = wb.active
# 1) 在第 1 行写一个跨 A1:E1 的大标题
ws["A1"] = "2026年9月销售报表"
ws.merge_cells("A1:E1")
# 合并后只有 A1 保留值,对 A1 设置居中
ws["A1"].alignment = Alignment(horizontal="center", vertical="center")
ws.row_dimensions[1].height = 28
# 2) 也可以用坐标元组合并
# ws.merge_cells(start_row=1, start_column=1, end_row=1, end_column=5)
# 3) 取消合并:把 B5:C5 拆开
if "B5:C5" in [str(r) for r in ws.merged_cells.ranges]:
ws.unmerge_cells("B5:C5")
# 4) 遍历当前所有合并区域,打印出来
print("当前合并区域:")
for r in ws.merged_cells.ranges:
print(" ", r)
# 5) 取消整表所有合并(数据清洗场景常用)
# for r in list(ws.merged_cells.ranges):
# ws.unmerge_cells(str(r))
wb.save(file_path)
print("合并/取消合并完成")
if __name__ == "__main__":
demo_merge(r"D:\reports\销售明细.xlsx")
代码讲解
ws.merge_cells("A1:E1")把 A1 到 E1 合并成一个格子;也可以用merge_cells(start_row=1, start_column=1, end_row=1, end_column=5)的坐标写法,循环合并时更方便。- 关键规则:合并后只有左上角单元格(这里是 A1)保留值,其它格子内容会被丢弃。所以标题要先写在 A1 再合并,或者合并后只对 A1 赋值。
- 合并后的居中要对左上角单元格设
Alignment,合并区域里其它格子设了也不显示。 ws.unmerge_cells("B5:C5")取消合并;取消后值仍然只在 B5,不会自动填充到 C5。ws.merged_cells.ranges返回当前所有合并区域,用来判断某块是否已合并,或遍历后批量取消。- 注释里的循环是数据清洗常用套路:把整张表的合并全部拆开,再按业务把左上角值向下填充,方便 pandas 读。
运行结果
打开文件,第 1 行 A1:E1 合并成一个居中的大标题「2026年9月销售报表」;B5:C5 如果之前合并过,被拆成两个独立格子;控制台打印当前所有合并区域。
注意事项
- 合并前如果区域内每个格子都有值,openpyxl 会保留左上角那个,其它静默丢弃,合并前先备份或确认数据。
- 取消合并不会把值回填到被拆开的格子,需要自己用代码把左上角值向下/向右填充。
- 读合并区域里非左上角的格子,
.value是None,不要误以为是空数据。 - 已经合并的区域再
merge_cells同一范围会报错,先判断或先 unmerge。 - 合并单元格参与排序、筛选时容易出问题,数据处理阶段建议先取消合并,展示阶段再合并。

更新时间:2026-09-15 09:05:38