使用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对象并设置换行样式。
修复方案
- 移除错误的
_argW、_argH手动赋值代码,创建Table时已通过colWidths参数设置列宽,无需重复修改 - 将所有单元格内容转为带换行样式的
Paragraph对象,实现文本自动换行 - 适配横向页面的可用宽度,合理分配列宽,避免表格超出页面范围
修复后的完整代码
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
相关产品推荐
相关产品推荐

