python-docx多段落格式设置时旧格式被覆盖问题咨询
问题:python-docx设置新段落格式时旧段落格式被覆盖
我尝试使用Python的python-docx模块批量修改Word文档段落格式,编写了如下代码:
from docx import Document from docx.shared import Pt from docx.shared import Inches from docx.enum.text import WD_PARAGRAPH_ALIGNMENT from docx.enum.section import WD_ORIENTATION from content import report_content, provinces, report_date, introduction, intro_content alignment_dict = {'justify': WD_PARAGRAPH_ALIGNMENT.JUSTIFY, 'center': WD_PARAGRAPH_ALIGNMENT.CENTER, 'centre': WD_PARAGRAPH_ALIGNMENT.CENTER, 'right': WD_PARAGRAPH_ALIGNMENT.RIGHT, 'left': WD_PARAGRAPH_ALIGNMENT.LEFT} orientation_dict = {'portrait': WD_ORIENTATION.PORTRAIT, 'landscape': WD_ORIENTATION.LANDSCAPE} document = Document() def change_orientation(orientation='portrait', set_left_margin=1.0, set_right_margin=1.0): section = document.sections[-1] new_width, new_height = section.page_height, section.page_width section.orientation = orientation_dict[orientation] section.page_width = new_width section.page_height = new_height section.left_margin = Inches(set_left_margin) section.right_margin = Inches(set_right_margin) def add_logo(path, align): document.add_picture(path, width=Inches(4.5), height=Inches(1.5)) last_paragraph = document.paragraphs[-1] last_paragraph.alignment = alignment_dict[align] def add_content(content, space_after, font_name='Arial', font_size=11, line_spacing=0, space_before=0, align='justify', keep_together=True, keep_with_next=False, page_break_before=False, widow_control=False, set_bold=False, set_italic=False, set_underline=False, set_all_caps=False): paragraph = document.add_paragraph(content) style = document.styles['Normal'] font = style.font font.name = font_name font.size = Pt(font_size) font.bold = set_bold font.italic = set_italic font.all_caps = set_all_caps font.underline = set_underline paragraph_format = paragraph.paragraph_format paragraph_format.alignment = alignment_dict.get(align.lower()) paragraph_format.space_before = Pt(space_before) paragraph_format.space_after = Pt(space_after) paragraph_format.line_spacing = line_spacing paragraph_format.keep_together = keep_together paragraph_format.keep_with_next = keep_with_next paragraph_format.page_break_before = page_break_before paragraph_format.widow_control = widow_control def create_numbered_list(): pass def add_subheading(subheading, level): document.add_heading(subheading, level) change_orientation(orientation='landscape', set_left_margin=0.5, set_right_margin=0.5) add_logo('logo.png', 'center') add_content(report_content, align='Center', space_before=40, space_after=20, line_spacing=1, font_name='Arial', set_bold=True, set_all_caps=True) add_content(provinces, align='Center', space_before=20, space_after=20, line_spacing=1, font_name='Arial', set_bold=True, set_all_caps=True) add_content(report_date, align='Center', space_before=20, space_after=20, line_spacing=1, font_name='Arial', set_bold=True, set_all_caps=True) document.add_page_break() add_subheading(introduction, level=1) add_content(intro_content, space_after=20, space_before=20) document.save('demo.docx')
但遇到了一个问题:每次调用add_content方法设置新段落的格式时,之前添加的旧段落格式都会被修改成当前段落的格式,没办法保留原有格式。请问这个问题的原因是什么?
解答
这个问题我之前也碰到过,核心原因其实很明确:你在add_content函数里直接修改了文档的全局Normal样式!
看这段关键代码:
style = document.styles['Normal'] font = style.font font.name = font_name font.size = Pt(font_size) # ... 其他字体属性修改
Word文档里所有默认创建的段落,都是基于Normal这个全局样式的。当你修改这个样式的字体、字号、加粗等属性时,所有使用该样式的段落——包括之前已经添加的旧段落——都会自动同步更新这些属性,这就导致了旧段落格式被覆盖的问题。
给你两种解决方案,按需选择:
1. 直接修改段落的Run属性(适合简单场景)
不需要碰全局样式,直接操作新添加段落的Run对象,这样只会影响当前段落:
def add_content(content, space_after, font_name='Arial', font_size=11, line_spacing=0, space_before=0, align='justify', keep_together=True, keep_with_next=False, page_break_before=False, widow_control=False, set_bold=False, set_italic=False, set_underline=False, set_all_caps=False): paragraph = document.add_paragraph(content) # 直接修改当前段落的run字体属性 run = paragraph.runs[0] run.font.name = font_name run.font.size = Pt(font_size) run.font.bold = set_bold run.font.italic = set_italic run.font.all_caps = set_all_caps run.font.underline = set_underline # 段落格式设置保持不变 paragraph_format = paragraph.paragraph_format paragraph_format.alignment = alignment_dict.get(align.lower()) paragraph_format.space_before = Pt(space_before) paragraph_format.space_after = Pt(space_after) paragraph_format.line_spacing = line_spacing paragraph_format.keep_together = keep_together paragraph_format.keep_with_next = keep_with_next paragraph_format.page_break_before = page_break_before paragraph_format.widow_control = widow_control
2. 创建自定义样式(适合需要重复复用格式的场景)
如果有多个段落需要用相同格式,推荐创建专属的自定义样式,既不会影响全局Normal样式,还能统一管理格式:
def add_content(content, space_after, font_name='Arial', font_size=11, line_spacing=0, space_before=0, align='justify', keep_together=True, keep_with_next=False, page_break_before=False, widow_control=False, set_bold=False, set_italic=False, set_underline=False, set_all_caps=False): # 生成唯一的样式名称,避免重复创建 style_name = f"CustomParaStyle_{font_name}_{font_size}_{set_bold}_{set_italic}" # 检查样式是否已存在,不存在则创建 if style_name not in document.styles: style = document.styles.add_style(style_name, 1) # 1代表段落样式类型 # 设置字体属性到自定义样式 font = style.font font.name = font_name font.size = Pt(font_size) font.bold = set_bold font.italic = set_italic font.all_caps = set_all_caps font.underline = set_underline # 设置段落格式到自定义样式 para_style = style.paragraph_format para_style.alignment = alignment_dict.get(align.lower()) para_style.space_before = Pt(space_before) para_style.space_after = Pt(space_after) para_style.line_spacing = line_spacing para_style.keep_together = keep_together para_style.keep_with_next = keep_with_next para_style.page_break_before = page_break_before para_style.widow_control = widow_control else: style = document.styles[style_name] # 使用自定义样式添加段落 paragraph = document.add_paragraph(content, style=style_name)
这样修改后,每个段落的格式就会独立保存,不会再互相影响了。
内容的提问来源于stack exchange,提问作者Arnab




