You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

遍历类属性(对象列表)时PDF表单字段更新异常问题

PDF表单提取仅最后一个字段更新的问题解决

问题场景

我需要从PDF中提取表单值,定义了如下类结构:

from typing import List, Tuple
import fitz
from pymupdf import Document

class FormField:
    def __init__(self, form_field_name: str):
        self.form_field_name: str = form_field_name
        self.form_field_value: str | None = None
        self.form_field_type: str | None = None

class Page:
    def __init__(self, page_name: str, page_no: int):
        self.page_name: str = page_name
        self.page_no: int = page_no
        self.list_of_forms: List[FormField] = []

    def add_form_fields(self, form_fields: List[FormField]):
        for form in form_fields:
            self.list_of_forms.append(form)

class PDFDocument:
    def __init__(self, path: str):
        self.path = path
        self.number_of_pages: int = 0
        self.list_of_pages: List[Page] = []
        self._document_instance: Document | None = None
    
    @property
    def document_instance(self) -> Document:
        if not self._document_instance:
            self._document_instance = fitz.open(self.path)  
            self.number_of_pages = self._document_instance.page_count
        return self._document_instance
   
    def add_pages(self, pages: List[Page]):
        for page in pages:
            self.list_of_pages.append(page)
    
    def search_for_form_value_and_type_in_pdf_document(self, field_name: str) -> Tuple[str, str]:
        for page in self.document_instance:
            for field in page.widgets(): # PyMuPDF获取表单元素的方法
                if field.field_name == field_name:
                    return field.field_value, field.field_type_string
        return "", ""  # 处理找不到字段的情况
    
    def apply_value_to_the_field(self, field: FormField, field_value: str, field_type: str):
        # 优化:直接操作传入的field对象,无需遍历列表
        field.form_field_value = field_value
        field.form_field_type = field_type

在main.py中定义PDF结构(指定要提取的字段):

document = PDFDocument("example.pdf")

first_page = Page("first page", 1)
document.add_pages([first_page])
    
field_1 = FormField("field_1")
field_2 = FormField("field_2")
first_page.add_form_fields([field_1, field_2])

问题代码

运行以下代码时,仅最后一个FormField对象被更新,其余字段的数值和类型未保存:

all_forms = []
for page in document.list_of_pages:
     for form in page.list_of_forms:
         all_forms.append(form)

# 这段代码仅为示例,实际循环处理时出错
for form in all_forms:
    value, type = (
        document.search_for_form_value_and_type_in_pdf_document(
            form.form_field_name
        )
    )
document.apply_value_to_the_field(form, field_value=value, field_type=type)

错误原因

document.apply_value_to_the_field方法调用放在了for循环外部,循环结束后form变量指向的是all_forms中的最后一个元素,因此只有最后一个字段被赋值。

解决方案

将赋值方法的调用放到for循环内部,确保每个字段都能被处理:

all_forms = []
for page in document.list_of_pages:
     for form in page.list_of_forms:
         all_forms.append(form)

# 修正:循环内部调用赋值方法
for form in all_forms:
    value, field_type = document.search_for_form_value_and_type_in_pdf_document(
        form.form_field_name
    )
    # 直接给当前form赋值,甚至可以不用apply_value_to_the_field方法
    form.form_field_value = value
    form.form_field_type = field_type

额外优化建议

  1. 缓存PDF文档实例:原document_instance属性每次调用都会重新打开PDF,优化后在__init__中缓存实例,避免重复IO操作。
  2. 简化赋值逻辑:既然已经拿到了form对象,直接给其属性赋值即可,无需调用apply_value_to_the_field方法(如果保留该方法,也可以简化为直接操作传入的field对象,无需遍历页面和字段列表)。
  3. 处理字段未找到的情况:在search_for_form_value_and_type_in_pdf_document中添加默认返回值,避免找不到字段时抛出异常。

内容的提问来源于stack exchange,提问作者ikari2k

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 21:35:04