
在办公自动化、数据报告生成、企业内部流程表中用 Python 操作 Word 表格早已不是新鲜话题。很多人已经会往 docx 文档里插入表格、逐格填写内容但做出来的表格往往还停留在 Word 默认的“黑白网格”状态既没有品牌感也需要在 Word 里手工调半天格式。真正遇到自定义表格样式时网上资料比较零散尤其在“应用样式”和“移除样式”这两个方向能讲完整的不多。本文将围绕“在 Word 表格中应用和移除自定义样式”这一主题展开使用 python-docx 作为主要工具。你会看到自定义表格样式从注册、设置基础属性到应用在表格上再到修改样式、批量切换样式、从样式库中安全删除样式的一整套流程。文章适合有 Python 基础、接触过办公自动化但没深入 table style 机制的读者也适合正在做文档模板系统的后端开发。下面我们就从概念开始一步一步搭建可运行的完整示例。1. 背景为什么要用 Python 管理 Word 表格样式先看一个经常出现的办公自动化场景。企业每周需要生成项目周报、销售清单或实验记录这些文档都有固定格式标题统一、表格边框统一、表头背景色统一、中文字体统一。如果每次在代码里手动创建表格后再对每个单元格设置边框、字体、对齐方式代码会长到难以维护。一旦模板的视觉规范发生变化你就需要改一大段循环代码而不是只改一个样式对象。这时 Word 的“表格样式”机制就有了明显优势。Word 表格样式相当于一个类型模板它定义了字体、字号、边框、底纹等视觉属性。你只需要在文档中定义好一种自定义样式之后创建的表格只要写上“使用这个样式”表格就会自动继承该样式的全部视觉规则。后续如果想调整只需要修改样式本身所有应用这个样式的表格会一起更新。用 Python 处理文档时应用和移除表格样式的需求通常出现在下面几类场景中。批量生成月报或数据表希望所有表格外观统一。把已有 Word 文档中的默认表格批量升级为公司规范样式。基于某个模板文件生成报价单、合同附表或成绩单。清理文档中不再需要的历史样式避免样式库过于杂乱。在这类需求中python-docx 提供了对表格、样式对象的编程入口。虽然它不像 Word VBA 那样可以直接操作 UI但实现对 docx 文件的高频批量处理足够用。2. 环境准备与基础概念2.1 环境说明与安装本文示例基于 Windows / macOS / Linux 均可运行核心依赖是 python-docx。建议使用 Python 3.8 以上版本。python-docx 不是 Python 标准库需要先安装。pip install python-docx安装完成后可以打印版本号确认是否成功。import docx print(docx.__version__)不同版本之间 API 可能存在细微差异如果后续代码报错可以先确认 python-docx 版本再按当前版本的 API 调整。本文以常见稳定版本为例重点说明配置思路与排错方向。需要注意python-docx 只能处理 .docx 格式不能读取老的 .doc 格式 Word 文件。如果业务中需要处理 .doc建议先借助 WPS 或 Microsoft Word 将文件另存为 .docx再交给 Python 处理。2.2 需要先理解样式 ID 与样式名称不是一个概念在 Word 的底层 XML 中每个样式节点都有两个关键属性。w:styleId程序内部使用的标识往往是英文或去空格后的字符串。w:name用户在 Word 界面里看到的名字。举个例子。内建的 “Table Grid” 样式在 styles.xml 中可能是下面这种结构。w:style w:typetable w:styleIdTableGrid w:name w:valTable Grid/ w:basedOn w:valNormalTable/ /w:stylepython-docx 允许你用样式名称去查找doc.styles[Table Grid]但在删除样式等底层操作中需要优先根据 styleId 定位 XML 节点因为 XML 里的引用通常使用 styleId。如果混用名称和 ID有可能出现“明明看到同名样式却删不掉”的情况。除了名称和 ID还有另一个概念内置样式与自定义样式。内置样式是 Word 自带的自定义样式是用户或程序创建的。内置样式通常不能直接删除即使通过 XML 强行删除Word 重新打开时也可能自动恢复或报兼容性提示。因此本文中的“删除自定义样式”操作应当只针对自己创建的样式不要对所有样式一视同仁地做删除。2.3 表格样式与直接设置格式的区别python-docx 中有两种常见的方式来控制表格外观。第一直接格式。直接对某个单元格或段落设置字体颜色、背景色等。这种方式见效快但代码量大且不会在 Word 的“表格样式库”中留下可复用条目。第二表格样式。先在 styles.xml 中注册一个样式再把样式赋值给表格。样式本身可以包含字体、边框、底纹等设置。表格引用样式后大部分外观由样式统一决定。两种方式不是互斥的。实际项目中经常出现“表格整体用自定义样式表头行再用直接格式单独设置底纹”的组合。这在后面的实战示例中会体现。3. 核心创建一个自定义表格样式3.1 注册自定义表格样式在 python-docx 中所有样式都注册在一个文档的 styles 集合下。要向文档添加自定义表格样式需要指定样式类型为 TABLE。from docx import Document from docx.enum.style import WD_STYLE_TYPE doc Document() table_style doc.styles.add_style(MyReportTable, WD_STYLE_TYPE.TABLE)执行这段代码后文档中其实已经有了一条名为 MyReportTable 的表格样式。但它目前几乎是空的没有边框、没有字体设置直接应用并不会让表格变好看。这时可以继续设置样式的基础属性。3.2 基于内置 Table Grid 创建边框python-docx 从零创建一个带边框的自定义表格样式比较繁琐因为需要在底层 XML 中构造 w:tblBorders。更推荐的做法是先找到内置的 Table Grid 样式把它作为自定义样式的基础。base_style doc.styles[Table Grid] table_style.base_style base_style设置 base_style 的效果是MyReportTable 会继承 Table Grid 的边框规则。也就是说只要把 MyReportTable 应用到表格上表格就会自动拥有 Table Grid 那样的黑色单线边框不需要在代码里逐条画线。为什么这样做比手工拼 XML 更合适原因是 Word 的样式继承机制会减少自定义样式体量也更容易在 Word 界面中理解和维护。如果后续需要微调边框样式建议直接在一个模板 docx 中用 Word 手动调整样式然后用 python-docx 打开模板使用它而不是在代码里拼接大量底层 XML。3.3 设置中文字体和字号表格样式还需要设置字体。python-docx 的 style.font 对象可以设置拉丁字体、字号、颜色等基础属性。但这里有一个新手很常踩的坑只设置 font.name 并不能保证中文字体生效。Word 的中文字体通常需要写进 w:eastAsia 属性python-docx 没有直接封装这个方法需要借助底层 XML。下面是一个完整示例。from docx.shared import Pt from docx.oxml.ns import qn def setup_chinese_table_style(table_style, ascii_fontMicrosoft YaHei, east_asia_font微软雅黑, font_size10.5): table_style.font.name ascii_font table_style.font.size Pt(font_size) rpr table_style.element.find(qn(w:rPr)) if rpr is not None: rfonts rpr.find(qn(w:rFonts)) if rfonts is not None: rfonts.set(qn(w:eastAsia), east_asia_font)其中 table_style.element 是该样式在 styles.xml 中对应的 XML 节点。设置 font.name 后python-docx 会生成 rPr/rFonts 节点。之后我们再去找到 rFonts并补充 eastAsia 字体这样 Word 显示中文时才会使用“微软雅黑”。如果这段代码在你的版本中没有找到 rPr也可以换成一句更直接的实现table_style.font.name 微软雅黑 table_style._element.rPr.rFonts.set(qn(w:eastAsia), 微软雅黑)两种写法目的一样只是前者更稳健后者更简洁。遇到报错时优先检查 python-docx 版本因为不同版本对底层节点暴露方式略有差异。4. 完整实战应用自定义样式生成报价表4.1 需求与表格结构我们现在模拟一个常见的办公场景生成一份产品报价表。表格要求如下。标题使用 Heading 1。表头固定在首行内容是物品、规格、数量、单价。表格整体应用上面定义的 MyReportTable 样式。表头行使用浅蓝色底纹让文档更有层次感。表头文字居中业务数据左对齐。表格结构大概是这样的一个 5 行 4 列的表格。第一行是表头后面四行是数据。4.2 创建文档和自定义样式把代码写在一个完整脚本中便于直接运行查看效果。先准备一个调用函数创建自定义样式。import docx from docx import Document from docx.enum.style import WD_STYLE_TYPE from docx.enum.text import WD_ALIGN_PARAGRAPH from docx.shared import Pt, RGBColor from docx.oxml import OxmlElement from docx.oxml.ns import qn def create_custom_table_style(doc, style_nameMyReportTable): style doc.styles.add_style(style_name, WD_STYLE_TYPE.TABLE) style.base_style doc.styles[Table Grid] style.font.name Microsoft YaHei style.font.size Pt(10.5) rpr style.element.find(qn(w:rPr)) if rpr is not None: rfonts rpr.find(qn(w:rFonts)) if rfonts is not None: rfonts.set(qn(w:eastAsia), 微软雅黑) return style函数先创建样式然后继承 Table Grid这样可以保证表格自带边框。如果是给内部系统生成文档推荐把微软雅黑这种字体名抽成函数参数方便不同公司或平台替换。4.3 插入数据并应用样式接着创建文档主体。为了让代码清晰我先用 add_table 创建一张空表填充数据后再将自定义样式赋值给 table.style。def generate_report(doc_pathquotation.docx): doc Document() doc.add_heading(产品报价表, level1) table doc.add_table(rows5, cols4) headers [物品, 规格, 数量, 单价] data [ [笔记本电脑, 14 英寸 16G512G, 10, 4999], [机械键盘, 87 键 有线, 20, 329], [无线鼠标, 静音版, 30, 89], [显示器支架, 碳钢 双屏, 15, 159], ] for col_index, header in enumerate(headers): cell table.rows[0].cells[col_index] cell.text header cell.paragraphs[0].alignment WD_ALIGN_PARAGRAPH.CENTER for row_index, row_data in enumerate(data, start1): for col_index, value in enumerate(row_data): cell table.rows[row_index].cells[col_index] cell.text value if col_index 1: cell.paragraphs[0].alignment WD_ALIGN_PARAGRAPH.LEFT else: cell.paragraphs[0].alignment WD_ALIGN_PARAGRAPH.CENTER # 样式定义放在填充数据之后逻辑上更接近“先有内容再定外观” custom_style create_custom_table_style(doc, MyReportTable) table.style custom_style doc.save(doc_path) print(f文档已生成{doc_path})这里有两个细节可以拆开说明。第一table.style 可以被赋值为样式对象。python-docx 也支持赋值字符串比如 table.style MyReportTable但使用样式对象可以明确保证引用的是刚创建的样本不容易出现因样式 ID 和名称混用而找不到样式的问题。第二add_table 时也可以直接传入样式名例如 doc.add_table(rows5, cols4, styleMyReportTable)。但那样语法会更长而且样式的创建代码要放在 add_table 之前。为了体现“给已有表格应用样式”这种更常见的场景我选择了先建表、填数据再设置 style 的流程。4.4 给表头单元格添加底纹目前表格已经从自定义样式继承了 Table Grid 的边框但表头还没有底纹。python-docx 没有直接提供 cell.shading xxx 这样的高级 API因此需要写一个底层辅助函数。这个函数在实际项目里复用率很高。def set_cell_shading(cell, fill_color): tc_pr cell._tc.get_or_add_tcPr() shd OxmlElement(w:shd) shd.set(qn(w:val), clear) shd.set(qn(w:color), auto) shd.set(qn(w:fill), fill_color) tc_pr.append(shd)调用方式是在填充表头之后对第一行每个单元格设置颜色。for col_index in range(len(headers)): set_cell_shading(table.rows[0].cells[col_index], D9E2F3)D9E2F3 是 Word 常见的水蓝色。fill_color 默认是十六进制颜色值不需要带 # 号。注意 set_cell_shading 属于直接格式它只影响当前单元格不会改变 MyReportTable 样式定义。这样做的原因是自定义表格样式的“条件格式”在 python-docx 中封装较弱处理复杂表头时直接用单元格底纹更直观。4.5 运行与验证执行主函数。if __name__ __main__: generate_report()运行后在同级目录会生成 quotation.docx。双击用 Word 打开可以看到如下效果。页面顶部有“产品报价表”标题。下方 5 行 4 列表格带有黑色单线边框。第一行文字居中并显示浅蓝色背景。表格内中文字体使用微软雅黑规格列左对齐其他列居中对齐。如果这些现象都出现了说明自定义表格样式已经成功应用。如果只有边框没有底纹或者字体仍是默认字体优先检查自定义样式是否真正加了 base_style以及中文字体是否设置了 eastAsia。5. 给已有 Word 表格批量应用或切换样式实际交付场景中更多时候需要处理的是“已经存在的文档”。例如一家公司收到一份旧的测试报告里面有