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

使用ReportLab生成PDF表格遇TypeError:float对象不支持元素赋值

问题调试:Python生成PDF表格时的TypeError错误

问题场景

尝试用Python生成横向布局PDF,打印至少6列的表格并实现列文本换行,运行generate_pdf2函数时触发TypeError,错误提示为'float' object does not support item assignment,错误出在尝试修改table._argW[i][j]与table._argH[j]的代码行。

原函数代码

from reportlab.lib.pagesizes import A4, landscape
from reportlab.platypus import SimpleDocTemplate, Paragraph, Table, TableStyle
from reportlab.lib.styles import getSampleStyleSheet
import pandas as pd

def generate_pdf2(df_list, titles, calculated_prices):
    # Create a landscape layout PDF
    doc = SimpleDocTemplate("pricing_information.pdf", pagesize=landscape(A4))

    # Initialize a list to hold the elements of the PDF
    elements = []

    # Define styles for the paragraphs
    styles = getSampleStyleSheet()
    normal_style = styles["Normal"]

    # Add title and information depending on variables
    for title, calculated_price in zip(titles, calculated_prices):
        elements.append(Paragraph(title, normal_style))
        elements.append(Paragraph(f"Calculated Price: {calculated_price}", normal_style))
        elements.append(Paragraph("", normal_style))  # Add empty line for spacing

    # Add tables with DataFrame titles and calculated prices
    for df, title, calculated_price in zip(df_list, titles, calculated_prices):
        # Convert DataFrame to a list of lists for the table
        data = [list(df.columns)] + df.astype(str).values.tolist()
        
        # Adjust column widths to fit content within the page
        col_widths = [(float(len(str(df[col].max()))) * 12.0) for col in df.columns]

        # Create a Table object with wrapped text
        table = Table(data, colWidths=col_widths)
        
        # Apply styles to the table
        table.setStyle(TableStyle([('BACKGROUND', (0, 0), (-1, 0), 'lightgrey'),
                                   ('TEXTCOLOR', (0, 0), (-1, 0), 'black'),
                                   ('ALIGN', (0, 0), (-1, -1), 'CENTER'),
                                   ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
                                   ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
                                   ('BACKGROUND', (0, 1), (-1, -1), 'white'),
                                   ('GRID', (0, 0), (-1, -1), 1, 'black')]))
        
        # Wrap text in cells
        width, height = A4
        for i in range(len(data)):
            for j in range(len(data[i])):
                table._argW[i][j] = col_widths[j]  # Set cell widths
                table._argH[j] = 20  # Set cell height for wrapping text
        
        # Add table to the elements list
        elements.append(Paragraph(title, normal_style))
        elements.append(table)
        elements.append(Paragraph("", normal_style))  # Add empty line for spacing

    # Build the PDF document
    doc.build(elements)

# Example usage:
# Create example DataFrames, titles, and calculated prices
df1 = pd.DataFrame({'A': [1, 2, 3], 'B': [4, 5, 6], 'C': [7, 8, 9], 'D': [10, 11, 12], 'E': [13, 14, 15], 'F': [16, 17, 18]})
df2 = pd.DataFrame({'X': [7, 8, 9], 'Y': [10, 11, 12], 'Z': [13, 14, 15], 'AA': [16, 17, 18], 'BB': [19, 20, 21], 'CC': [22, 23, 24]})
df3 = pd.DataFrame({'M': [13, 14, 15], 'N': [16, 17, 18], 'O': [19, 20, 21], 'P': [22, 23, 24], 'Q': [25, 26, 27], 'R': [28, 29, 30]})
df_list = [df1, df2, df3]
titles = ['DataFrame 1', 'DataFrame 2', 'DataFrame 3']
calculated_prices = [100, 200, 300]  # Example calculated prices

# Generate PDF
generate_pdf2(df_list, titles, calculated_prices)

错误信息

<ipython-input-13-20731d70741e> in generate_pdf2(df_list, titles, calculated_prices)
    105         for i in range(len(data)):
    106             for j in range(len(data[i])):
--> 107                 table._argW[i][j] = col_widths[j]  # Set cell widths
    108                 table._argH[j] = 20  # Set cell height for wrapping text
    109 
TypeError: 'float' object does not support item assignment

错误原因

ReportLab的Table对象中:

  • _argW是一维列表,每个元素是对应列的宽度(float类型),并非二维数组,所以table._argW[i]取到的是第i列的宽度值(float),无法通过[j]进行赋值
  • _argH是一维列表,每个元素是对应行的高度(float类型),索引应该按行号而非列号,且手动修改私有属性本身就不符合封装规范,容易引发异常

另外,原代码中直接用字符串作为单元格内容,无法实现自动换行,需要将内容转为Paragraph对象并设置换行样式。

修复方案

  1. 移除错误的_argW、_argH手动赋值代码,创建Table时已通过colWidths参数设置列宽,无需重复修改
  2. 将所有单元格内容转为带换行样式的Paragraph对象,实现文本自动换行
  3. 适配横向页面的可用宽度,合理分配列宽,避免表格超出页面范围

修复后的完整代码

from reportlab.lib.pagesizes import A4, landscape
from reportlab.platypus import SimpleDocTemplate, Paragraph, Table, TableStyle
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.units import mm
import pandas as pd

def generate_pdf2(df_list, titles, calculated_prices):
    # 横向A4页面,获取页面宽高(landscape后宽是原A4的高)
    page_width, page_height = landscape(A4)
    # 页面左右边距,留20mm
    margin = 20 * mm
    available_width = page_width - 2 * margin

    doc = SimpleDocTemplate("pricing_information.pdf", pagesize=landscape(A4), leftMargin=margin, rightMargin=margin)
    elements = []
    styles = getSampleStyleSheet()
    
    # 普通文本样式
    normal_style = styles["Normal"]
    # 表格单元格样式:设置自动换行,对齐方式
    cell_style = styles["Normal"]
    cell_style.wordWrap = 'CJK'  # 支持中英文换行
    cell_style.alignment = 1  # 居中对齐(0左,1中,2右)

    # 添加标题和价格信息
    for title, calculated_price in zip(titles, calculated_prices):
        elements.append(Paragraph(title, normal_style))
        elements.append(Paragraph(f"Calculated Price: {calculated_price}", normal_style))
        elements.append(Paragraph("", normal_style))

    # 处理每个DataFrame生成表格
    for df, title, calculated_price in zip(df_list, titles, calculated_prices):
        # 将表头和单元格内容都转为Paragraph对象,实现换行
        header = [Paragraph(col, cell_style) for col in df.columns]
        rows = []
        for _, row in df.iterrows():
            row_cells = [Paragraph(str(val), cell_style) for val in row.values]
            rows.append(row_cells)
        data = [header] + rows

        # 计算列宽:平均分配可用宽度,确保总宽度不超过页面
        col_count = len(df.columns)
        col_widths = [available_width / col_count for _ in range(col_count)]

        # 创建表格
        table = Table(data, colWidths=col_widths)
        
        # 设置表格样式
        table.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), 'lightgrey'),
            ('TEXTCOLOR', (0, 0), (-1, 0), 'black'),
            ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
            ('BOTTOMPADDING', (0, 0), (-1, 0), 12),
            ('BACKGROUND', (0, 1), (-1, -1), 'white'),
            ('GRID', (0, 0), (-1, -1), 1, 'black'),
            ('VALIGN', (0, 0), (-1, -1), 'MIDDLE')  # 垂直居中
        ]))

        # 添加表格到PDF元素
        elements.append(Paragraph(title, normal_style))
        elements.append(table)
        elements.append(Paragraph("", normal_style))

    # 生成PDF
    doc.build(elements)

# 示例使用(包含6列数据)
df1 = pd.DataFrame({
    'A': [1, 2, 3], 
    'B': ["较长文本内容测试换行", "中等长度文本", "短文本"], 
    'C': [7, 8, 9], 
    'D': [10, 11, 12], 
    'E': ["这是一段非常长的测试文本,用来验证单元格是否能够自动换行显示完整内容", "普通文本", "短"], 
    'F': [16, 17, 18]
})
df2 = pd.DataFrame({
    'X': [7, 8, 9], 
    'Y': [10, 11, 12], 
    'Z': [13, 14, 15], 
    'AA': [16, 17, 18], 
    'BB': [19, 20, 21], 
    'CC': ["测试换行的长文本内容,看看是否能正确显示在单元格内", "正常文本", "短内容"]
})
df3 = pd.DataFrame({
    'M': [13, 14, 15], 
    'N': [16, 17, 18], 
    'O': [19, 20, 21], 
    'P': [22, 23, 24], 
    'Q': [25, 26, 27], 
    'R': [28, 29, 30]
})
df_list = [df1, df2, df3]
titles = ['DataFrame 1', 'DataFrame 2', 'DataFrame 3']
calculated_prices = [100, 200, 300]

generate_pdf2(df_list, titles, calculated_prices)

关键修改说明

  • 把单元格内容全部转为Paragraph对象,并设置wordWrap='CJK'实现中英文自动换行
  • 基于横向页面的可用宽度计算列宽,避免表格超出页面范围
  • 移除了对Table私有属性_argW、_argH的错误修改,改用官方API规范实现样式设置
  • 添加了垂直居中对齐,提升表格美观度

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 23:54:59