导出字典到CSV时遇TypeError:列表不支持格式字符串传递
Python支出追踪器CSV功能报错修复:TypeError: unsupported format string passed to list.format
错误原因分析
- 价格格式化错误:
self._data字典中值为列表类型(如"Water": [24]),但fill_table方法中直接用f"{price:.2f}"对列表做浮点数格式化,列表不支持该操作,触发TypeError。 - CSV写入逻辑问题:使用
csv.DictWriter时,传入的fieldnames是self._data的键,但writerow(self._data)会直接写入列表值,导致CSV内容不符合预期;同时export按钮错误绑定了clear_table函数,完全未实现导出功能。 - 次要错误:
add_element方法中的错误提示文字逻辑矛盾,"That is not an invalid input"应为"That is not a valid input"。
修复步骤
1. 修正数据结构
将self._data中的列表值改为单个数值(每个支出条目仅对应一个价格):
self._data = {"Water": 24, "Rent": 1000, "Coffee": 30, "Grocery": 300, "Phone": 45, "Internet": 70}
2. 修复CSV初始写入逻辑
替换初始化中的CSV写入代码,确保表头和数据正确写入:
with open("aib_october.csv", 'w', newline='') as file: fieldnames = ["Description", "Price"] writer = csv.DictWriter(file, fieldnames=fieldnames) writer.writeheader() for desc, price in self._data.items(): writer.writerow({"Description": desc, "Price": price})
3. 添加正确的CSV导出函数
新增导出函数,并修正export按钮的信号绑定:
@Slot() def export_to_csv(self): with open("expenses_export.csv", 'w', newline='') as file: writer = csv.writer(file) writer.writerow(["Description", "Price"]) for row in range(self.table.rowCount()): desc = self.table.item(row, 0).text() price = self.table.item(row, 1).text() writer.writerow([desc, price]) print("数据已成功导出到expenses_export.csv")
在__init__方法中修改按钮绑定:
self.export.clicked.connect(self.export_to_csv)
4. 修正错误提示文字
在add_element方法中,将错误提示改为:
print("That is not a valid input:", price, "Make sure to enter a price!")
修复后完整代码
import csv import sys from PySide6.QtCore import Qt, Slot from PySide6.QtGui import QAction , QPainter from PySide6.QtWidgets import (QApplication, QHeaderView, QHBoxLayout, QLabel, QLineEdit, QMainWindow, QPushButton, QTableWidget, QTableWidgetItem, QVBoxLayout, QWidget) from PySide6.QtCharts import QChartView, QPieSeries, QChart class Widget(QWidget): def __init__(self): QWidget.__init__(self) self.items = 0 # 修正数据结构:值为单个数值而非列表 self._data = {"Water": 24, "Rent": 1000, "Coffee": 30, "Grocery": 300, "Phone": 45, "Internet": 70} # 修正CSV初始写入逻辑 with open("aib_october.csv", 'w', newline='') as file: fieldnames = ["Description", "Price"] writer = csv.DictWriter(file, fieldnames=fieldnames) writer.writeheader() for desc, price in self._data.items(): writer.writerow({"Description": desc, "Price": price}) # Left Widget self.table = QTableWidget() self.table.setColumnCount(2) self.table.setHorizontalHeaderLabels(["Description", "Price"]) self.table.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # Chart self.chart_view = QChartView() self.chart_view.setRenderHint(QPainter.Antialiasing) # Right Widget self.description = QLineEdit() self.price = QLineEdit() self.add = QPushButton("Add") self.clear = QPushButton("Clear") self.quit = QPushButton("Quit") self.plot = QPushButton("Plot") self.export = QPushButton("export") # Disabling 'Add' button self.add.setEnabled(False) self.right = QVBoxLayout() self.right.addWidget(QLabel("Description")) self.right.addWidget(self.description) self.right.addWidget(QLabel("Price")) self.right.addWidget(self.price) self.right.addWidget(self.add) self.right.addWidget(self.plot) self.right.addWidget(self.chart_view) self.right.addWidget(self.export) self.right.addWidget(self.clear) self.right.addWidget(self.quit) # QWidget Layout self.layout = QHBoxLayout() self.layout.addWidget(self.table) self.layout.addLayout(self.right) # Set the layout to the QWidget self.setLayout(self.layout) # Signals and Slots self.add.clicked.connect(self.add_element) self.quit.clicked.connect(self.quit_application) self.plot.clicked.connect(self.plot_data) self.clear.clicked.connect(self.clear_table) # 修正export按钮绑定 self.export.clicked.connect(self.export_to_csv) self.description.textChanged[str].connect(self.check_disable) self.price.textChanged[str].connect(self.check_disable) # Fill example data self.fill_table() @Slot() def add_element(self): des = self.description.text() price = self.price.text() try: price_item = QTableWidgetItem(f"{float(price):.2f}") price_item.setTextAlignment(Qt.AlignRight) self.table.insertRow(self.items) description_item = QTableWidgetItem(des) self.table.setItem(self.items, 0, description_item) self.table.setItem(self.items, 1, price_item) self.description.setText("") self.price.setText("") self.items += 1 except ValueError: # 修正错误提示文字 print("That is not a valid input:", price, "Make sure to enter a price!") @Slot() def check_disable(self, x): if not self.description.text() or not self.price.text(): self.add.setEnabled(False) else: self.add.setEnabled(True) @Slot() def plot_data(self): # Get table information series = QPieSeries() for i in range(self.table.rowCount()): text = self.table.item(i, 0).text() number = float(self.table.item(i, 1).text()) series.append(text, number) chart = QChart() chart.addSeries(series) chart.legend().setAlignment(Qt.AlignLeft) self.chart_view.setChart(chart) @Slot() def quit_application(self): QApplication.quit() def fill_table(self, data=None): data = self._data if not data else data for desc, price in data.items(): description_item = QTableWidgetItem(desc) # 现在price是单个数值,格式化正常 price_item = QTableWidgetItem(f"{price:.2f}") price_item.setTextAlignment(Qt.AlignRight) self.table.insertRow(self.items) self.table.setItem(self.items, 0, description_item) self.table.setItem(self.items, 1, price_item) self.items += 1 @Slot() def clear_table(self): self.table.setRowCount(0) self.items = 0 # 新增CSV导出函数 @Slot() def export_to_csv(self): with open("expenses_export.csv", 'w', newline='') as file: writer = csv.writer(file) writer.writerow(["Description", "Price"]) for row in range(self.table.rowCount()): desc = self.table.item(row, 0).text() price = self.table.item(row, 1).text() writer.writerow([desc, price]) print("数据已成功导出到expenses_export.csv") class MainWindow(QMainWindow): def __init__(self, widget): QMainWindow.__init__(self) self.setWindowTitle("The pynancial advisor") # Menu self.menu = self.menuBar() self.file_menu = self.menu.addMenu("File") # Exit QAction exit_action = QAction("Exit", self) exit_action.setShortcut("Ctrl+Q") exit_action.triggered.connect(self.exit_app) self.file_menu.addAction(exit_action) self.setCentralWidget(widget) @Slot() def exit_app(self, checked): QApplication.quit() if __name__ == "__main__": # Qt Application app = QApplication(sys.argv) # QWidget widget = Widget() # QMainWindow using QWidget as central widget window = MainWindow(widget) window.resize(800, 600) window.show() # Execute application sys.exit(app.exec())
内容的提问来源于stack exchange,提问作者BLAZE GAMING
相关产品推荐
相关产品推荐

