python-docx: Create, Read, and Edit Word Documents
Learn how to create, read, and edit Word documents programmatically with python-docx. Covers paragraphs, runs, styles, tables, images, headers, and footers.
Automating Word documents is a common requirement for developers who need to generate reports, extract data from .docx files, or modify existing documents without manual intervention. This article explains how to create, read, and edit Word documents with the python-docx library. It covers the core operations: creating a new document, reading existing content, editing paragraphs and runs, applying styles, and adding tables and images. You will also learn about common pitfalls and compatibility considerations that affect real-world usage.
Installing python-docx and Loading a Document
Install python-docx with pip:
pip install python-docx
Then import the Document class:
from docx import Document
To load an existing document, pass the file path to the constructor:
doc = Document("existing.docx")
To create a new, empty document, call Document() with no arguments:
doc = Document()
The Document object represents the entire .docx file, including sections, paragraphs, tables, and styles. All modifications are held in memory until you call doc.save(). This means you can work with a document without affecting the original file until you explicitly write it out.
Creating a New Word Document
Start with an empty document and add content using methods like add_heading and add_paragraph:
from docx import Document doc = Document() doc.add_heading("Project Report", level=0) doc.add_paragraph("This is the first paragraph.") doc.add_paragraph("This is a second paragraph with some text.") doc.save("report.docx")
add_heading creates a heading with a specified level; level 0 is the document title. add_paragraph adds a normal paragraph. The document is saved to a file with save(). You can also insert page breaks:
doc.add_page_break()
This is useful when you want to control the flow of content across pages.
Reading Document Content
To read text from an existing document, iterate over doc.paragraphs:
doc = Document("report.docx") for para in doc.paragraphs: print(para.text)
This iterates over paragraphs in the document body. Paragraphs inside tables are not included in doc.paragraphs; use doc.tables if you need to read table content as well.
Each paragraph has a text property that returns the combined text of all its runs. If you need to preserve or inspect formatting, examine runs individually:
for para in doc.paragraphs: for run in para.runs: print(run.text, run.bold, run.italic)
Runs are contiguous segments of text with identical formatting. This distinction matters when you need to modify only part of a paragraph while leaving the rest unchanged.
Editing Paragraphs and Runs
You can modify the text of a run directly:
doc = Document("report.docx") para = doc.paragraphs[0] para.runs[0].text = "Updated text" doc.save("report_updated.docx")
To add a new run with specific formatting, use add_run on a paragraph:
para = doc.paragraphs[0] run = para.add_run("Newly added run") run.bold = True
If you need to replace the entire paragraph text, you can clear existing runs and add a new one:
para = doc.paragraphs[0] for run in para.runs: run.text = "" para.add_run("Completely new paragraph text")
Setting run.text to an empty string leaves empty runs in the document. A cleaner approach is to remove the underlying XML elements:
for run in para.runs: run._r.getparent().remove(run._r) para.add_run("Completely new paragraph text")
This removes the run elements entirely, avoiding stray empty runs.
Applying Styles and Formatting
python-docx supports built-in styles such as 'Normal', 'Heading 1', 'Title', and many others. Assign a style to a paragraph using the style property:
para = doc.add_paragraph("Styled text") para.style = doc.styles['Heading 1']
You can also modify font properties directly on runs:
from docx.shared import RGBColor, Pt run = para.add_run("Bold and red") run.bold = True run.font.color.rgb = RGBColor(0xFF, 0x00, 0x00) run.font.size = Pt(14)
RGBColor and Pt come from docx.shared. For paragraph alignment, use the WD_ALIGN_PARAGRAPH enum:
from docx.enum.text import WD_ALIGN_PARAGRAPH para.alignment = WD_ALIGN_PARAGRAPH.CENTER
These tools give you fine-grained control over the visual appearance of your document.
Adding Tables and Images
Tables are created with add_table:
table = doc.add_table(rows=2, cols=3) table.cell(0, 0).text = "Name" table.cell(0, 1).text = "Age" table.cell(1, 0).text = "Alice" table.cell(1, 1).text = "30"
You can add rows dynamically with table.add_row(). To add a column, use table.add_column(width), where width is a length value such as Inches(2) from docx.shared. For images, use add_picture:
from docx.shared import Inches doc.add_picture("chart.png", width=Inches(6))
The image is embedded in the document. You can control its size by specifying width and/or height.
Working with Sections, Headers, and Footers
A document can contain multiple sections, each with its own page layout. Access sections via doc.sections:
section = doc.sections[0] section.top_margin = Inches(1) section.bottom_margin = Inches(1)
Headers and footers belong to sections:
header = section.header header_para = header.paragraphs[0] header_para.text = "Company Confidential"
Footers work the same way with section.footer. This is useful for adding page numbers, titles, or disclaimers to every page.
Compatibility and Performance Considerations
python-docx works with .docx files, which use the Office Open XML format. It does not support the older binary .doc format. If you need to handle .doc files, you must convert them to .docx first or use a different library such as pywin32 on Windows.
When working with large documents, be aware that python-docx loads the entire file into memory. For very large files, this can be memory-intensive; the library has no built-in streaming mode, so test with representative files and use lower-level XML tools if necessary. Also, when modifying existing documents, save to a new filename unless you intend to overwrite the original; python-docx does not provide an undo feature.
Finally, test your code with different Word versions. Some formatting features may not render identically across all versions, especially when using custom styles or complex table layouts. Because python-docx operates on the underlying XML structure, edge cases can appear with unusual document structures.