本文目录导读:

我来帮你写一个收支记账记录脚本,提供三种不同复杂度的方案,从简单到功能完整。
简易版本(控制台应用)
# simple_accounting.py
import json
from datetime import datetime
import os
class SimpleAccounting:
def __init__(self, filename="records.json"):
self.filename = filename
self.records = self.load_records()
def load_records(self):
if os.path.exists(self.filename):
with open(self.filename, 'r', encoding='utf-8') as f:
return json.load(f)
return []
def save_records(self):
with open(self.filename, 'w', encoding='utf-8') as f:
json.dump(self.records, f, ensure_ascii=False, indent=2)
def add_record(self, type_, amount, category, note=""):
record = {
"id": len(self.records) + 1,
"type": type_, # "收入" or "支出"
"amount": float(amount),
"category": category,
"note": note,
"date": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
self.records.append(record)
self.save_records()
print(f"✅ 记录成功:{type_} ¥{amount} - {category}")
def show_summary(self):
total_income = sum(r["amount"] for r in self.records if r["type"] == "收入")
total_expense = sum(r["amount"] for r in self.records if r["type"] == "支出")
balance = total_income - total_expense
print(f"\n📊 收支汇总")
print(f"{'─' * 30}")
print(f"💰 总收入:¥{total_income:.2f}")
print(f"💸 总支出:¥{total_expense:.2f}")
print(f"💎 余额: ¥{balance:.2f}")
print(f"📝 总记录:{len(self.records)} 条")
def show_records(self, limit=10):
print(f"\n📋 最近记录(最新{limit}条)")
print(f"{'─' * 60}")
for record in self.records[-limit:]:
print(f"{record['date'][:10]} | {record['type']:^4} | ¥{record['amount']:>8.2f} | {record['category']:^8} | {record['note']}")
def search(self, keyword):
results = [r for r in self.records if keyword in str(r)]
print(f"\n🔍 搜索:'{keyword}' - 找到 {len(results)} 条结果")
for r in results:
print(f"{r['date'][:10]} | {r['type']:^4} | ¥{r['amount']:>8.2f} | {r['category']:^8} | {r['note']}")
def main():
app = SimpleAccounting()
while True:
print(f"\n{'=' * 40}")
print("📒 简易记账本")
print(f"{'=' * 40}")
print("1. 添加收入")
print("2. 添加支出")
print("3. 查看汇总")
print("4. 查看记录")
print("5. 搜索记录")
print("6. 退出")
choice = input("\n请选择操作 (1-6): ").strip()
if choice == "1" or choice == "2":
try:
amount = input("金额: ")
category = input("类别 (工资/兼职/奖金/其他): ")
note = input("备注 (可选): ")
app.add_record("收入" if choice == "1" else "支出", amount, category, note)
except ValueError:
print("❌ 金额输入错误!")
elif choice == "3":
app.show_summary()
elif choice == "4":
app.show_records()
elif choice == "5":
keyword = input("输入搜索关键词: ")
app.search(keyword)
elif choice == "6":
print("👋 再见!")
break
input("\n按回车键继续...")
if __name__ == "__main__":
main()
更多功能的版本
# advanced_accounting.py
import json
import csv
from datetime import datetime, date
import os
from collections import defaultdict
class AccountingSystem:
def __init__(self, filename="accounting_data.json"):
self.filename = filename
self.data = self.load_data()
def load_data(self):
"""加载数据"""
if os.path.exists(self.filename):
with open(self.filename, 'r', encoding='utf-8') as f:
return json.load(f)
return {
"records": [],
"categories": {
"收入": ["工资", "奖金", "兼职", "投资", "红包", "其他"],
"支出": ["餐饮", "交通", "购物", "娱乐", "住房", "医疗", "教育", "其他"]
}
}
def save_data(self):
"""保存数据"""
with open(self.filename, 'w', encoding='utf-8') as f:
json.dump(self.data, f, ensure_ascii=False, indent=2)
def add_record(self, type_, amount, category, note="", date_str=None):
"""添加记录"""
if date_str is None:
date_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
record = {
"id": len(self.data["records"]) + 1,
"type": type_,
"amount": float(amount),
"category": category,
"note": note,
"date": date_str,
"created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
self.data["records"].append(record)
self.save_data()
return record
def get_statistics(self, start_date=None, end_date=None):
"""获取统计信息"""
records = self.data["records"]
# 如果指定日期范围,过滤记录
if start_date and end_date:
records = [r for r in records if start_date <= r["date"][:10] <= end_date]
# 计算各类统计
total_income = sum(r["amount"] for r in records if r["type"] == "收入")
total_expense = sum(r["amount"] for r in records if r["type"] == "支出")
# 按类别统计
income_by_category = defaultdict(float)
expense_by_category = defaultdict(float)
for r in records:
if r["type"] == "收入":
income_by_category[r["category"]] += r["amount"]
else:
expense_by_category[r["category"]] += r["amount"]
# 按月统计
monthly_stats = defaultdict(lambda: {"收入": 0, "支出": 0})
for r in records:
month = r["date"][:7]
monthly_stats[month][r["type"]] += r["amount"]
return {
"total_records": len(records),
"total_income": total_income,
"total_expense": total_expense,
"balance": total_income - total_expense,
"income_by_category": dict(income_by_category),
"expense_by_category": dict(expense_by_category),
"monthly_stats": dict(monthly_stats)
}
def export_to_csv(self, filename="accounting_export.csv"):
"""导出为CSV"""
with open(filename, 'w', newline='', encoding='utf-8-sig') as f:
writer = csv.writer(f)
writer.writerow(["ID", "类型", "金额", "类别", "备注", "日期"])
for r in self.data["records"]:
writer.writerow([r["id"], r["type"], r["amount"], r["category"], r["note"], r["date"]])
print(f"✅ 已导出到 {filename}")
def show_detailed_report(self):
"""显示详细报表"""
stats = self.get_statistics()
print(f"\n{'=' * 50}")
print("📊 详细财务报表")
print(f"{'=' * 50}")
print(f"📍 统计周期:全部")
print(f"📝 总记录数:{stats['total_records']}")
print(f"💰 总收入:¥{stats['total_income']:.2f}")
print(f"💸 总支出:¥{stats['total_expense']:.2f}")
print(f"💎 结余:¥{stats['balance']:.2f}")
print(f"\n📈 收入分类明细:")
print(f"{'─' * 40}")
for cat, amount in sorted(stats['income_by_category'].items(), key=lambda x: x[1], reverse=True):
percentage = (amount / stats['total_income'] * 100) if stats['total_income'] > 0 else 0
print(f" {cat:^8}: ¥{amount:>8.2f} ({percentage:.1f}%)")
print(f"\n📉 支出分类明细:")
print(f"{'─' * 40}")
for cat, amount in sorted(stats['expense_by_category'].items(), key=lambda x: x[1], reverse=True):
percentage = (amount / stats['total_expense'] * 100) if stats['total_expense'] > 0 else 0
print(f" {cat:^8}: ¥{amount:>8.2f} ({percentage:.1f}%)")
print(f"\n📅 月度收支趋势:")
print(f"{'─' * 40}")
for month in sorted(stats['monthly_stats'].keys()):
m_stats = stats['monthly_stats'][month]
balance = m_stats['收入'] - m_stats['支出']
print(f" {month}: 收入¥{m_stats['收入']:>8.2f} | 支出¥{m_stats['支出']:>8.2f} | 结余¥{balance:>8.2f}")
def main():
app = AccountingSystem()
while True:
print(f"\n{'=' * 50}")
print("📒 智能记账系统")
print(f"{'=' * 50}")
print("1. 📝 添加收入记录")
print("2. 📝 添加支出记录")
print("3. 📊 查看财务报表")
print("4. 📋 查看最近记录")
print("5. 🔍 搜索记录")
print("6. 📤 导出CSV")
print("7. ⚙️ 管理类别")
print("8. 🗑️ 删除记录")
print("0. 🚪 退出")
choice = input("\n请选择操作 (0-8): ").strip()
if choice == "1":
try:
amount = float(input("💰 金额: "))
print("类别:")
for i, cat in enumerate(app.data["categories"]["收入"], 1):
print(f" {i}. {cat}")
cat_choice = int(input("选择类别编号: ")) - 1
category = app.data["categories"]["收入"][cat_choice]
note = input("📝 备注 (可选): ")
app.add_record("收入", amount, category, note)
print("✅ 收入记录成功!")
except (ValueError, IndexError) as e:
print(f"❌ 输入错误:{e}")
elif choice == "2":
try:
amount = float(input("💰 金额: "))
print("类别:")
for i, cat in enumerate(app.data["categories"]["支出"], 1):
print(f" {i}. {cat}")
cat_choice = int(input("选择类别编号: ")) - 1
category = app.data["categories"]["支出"][cat_choice]
note = input("📝 备注 (可选): ")
app.add_record("支出", amount, category, note)
print("✅ 支出记录成功!")
except (ValueError, IndexError) as e:
print(f"❌ 输入错误:{e}")
elif choice == "3":
app.show_detailed_report()
elif choice == "4":
limit = input("显示多少条?(默认10): ")
limit = int(limit) if limit.strip() else 10
for r in app.data["records"][-limit:]:
print(f"{r['date'][:10]} | {r['type']:^4} | ¥{r['amount']:>8.2f} | {r['category']:^8} | {r['note']}")
elif choice == "5":
keyword = input("🔍 搜索关键词: ")
results = [r for r in app.data["records"] if keyword in str(r)]
print(f"找到 {len(results)} 条结果:")
for r in results:
print(f"{r['date'][:10]} | {r['type']:^4} | ¥{r['amount']:>8.2f} | {r['category']:^8} | {r['note']}")
elif choice == "6":
app.export_to_csv()
elif choice == "7":
print("类别管理功能开发中...")
elif choice == "8":
try:
id_to_delete = int(input("输入要删除的记录ID: "))
app.data["records"] = [r for r in app.data["records"] if r["id"] != id_to_delete]
app.save_data()
print(f"✅ 已删除记录 #{id_to_delete}")
except ValueError:
print("❌ 无效的ID")
elif choice == "0":
print("👋 感谢使用,再见!")
break
input("\n按回车键继续...")
if __name__ == "__main__":
main()
带GUI界面的版本(使用tkinter)
如果你想要图形界面,这里是一个简单的GUI版本:
# gui_accounting.py
import tkinter as tk
from tkinter import ttk, messagebox
from datetime import datetime
import json
import os
class AccountingApp:
def __init__(self, root):
self.root = root
self.root.title("简易记账本")
self.root.geometry("800x600")
self.filename = "records.json"
self.records = self.load_records()
self.setup_ui()
def load_records(self):
if os.path.exists(self.filename):
with open(self.filename, 'r', encoding='utf-8') as f:
return json.load(f)
return []
def save_records(self):
with open(self.filename, 'w', encoding='utf-8') as f:
json.dump(self.records, f, ensure_ascii=False, indent=2)
def setup_ui(self):
# 创建主框架
main_frame = ttk.Frame(self.root, padding="10")
main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
# 输入区域
input_frame = ttk.LabelFrame(main_frame, text="添加记录", padding="10")
input_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)
# 金额输入
ttk.Label(input_frame, text="金额:").grid(row=0, column=0, sticky=tk.W)
self.amount_var = tk.StringVar()
ttk.Entry(input_frame, textvariable=self.amount_var, width=15).grid(row=0, column=1, padx=5)
# 类型选择
ttk.Label(input_frame, text="类型:").grid(row=0, column=2, sticky=tk.W)
self.type_var = tk.StringVar(value="支出")
ttk.Combobox(input_frame, textvariable=self.type_var, values=["收入", "支出"], width=10, state="readonly").grid(row=0, column=3, padx=5)
# 类别选择
ttk.Label(input_frame, text="类别:").grid(row=0, column=4, sticky=tk.W)
self.category_var = tk.StringVar()
category_combo = ttk.Combobox(input_frame, textvariable=self.category_var, width=15, state="readonly")
category_combo.grid(row=0, column=5, padx=5)
# 根据类型更新类别
def update_categories(*args):
if self.type_var.get() == "收入":
category_combo['values'] = ["工资", "奖金", "兼职", "投资", "红包", "其他"]
else:
category_combo['values'] = ["餐饮", "交通", "购物", "娱乐", "住房", "医疗", "教育", "其他"]
self.category_var.set("")
self.type_var.trace('w', update_categories)
# 备注输入
ttk.Label(input_frame, text="备注:").grid(row=0, column=6, sticky=tk.W)
self.note_var = tk.StringVar()
ttk.Entry(input_frame, textvariable=self.note_var, width=20).grid(row=0, column=7, padx=5)
# 添加按钮
ttk.Button(input_frame, text="添加记录", command=self.add_record).grid(row=0, column=8, padx=5)
# 统计信息区域
stats_frame = ttk.LabelFrame(main_frame, text="统计信息", padding="10")
stats_frame.grid(row=1, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)
self.stats_labels = {}
stats_info = [("总收入", "total_income"), ("总支出", "total_expense"), ("结余", "balance")]
for i, (label, key) in enumerate(stats_info):
ttk.Label(stats_frame, text=f"{label}:").grid(row=0, column=i*2, padx=10)
self.stats_labels[key] = ttk.Label(stats_frame, text="¥0.00", font=("Arial", 10, "bold"))
self.stats_labels[key].grid(row=0, column=i*2+1, padx=5)
# 记录列表
list_frame = ttk.LabelFrame(main_frame, text="收支记录", padding="10")
list_frame.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)
# 创建表格
columns = ("日期", "类型", "金额", "类别", "备注")
self.tree = ttk.Treeview(list_frame, columns=columns, show="headings", height=15)
for col in columns:
self.tree.heading(col, text=col)
self.tree.column(col, width=100)
self.tree.column("日期", width=120)
self.tree.column("金额", width=100)
self.tree.pack(fill=tk.BOTH, expand=True)
# 滚动条
scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL, command=self.tree.yview)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.tree.configure(yscrollcommand=scrollbar.set)
# 操作按钮
button_frame = ttk.Frame(main_frame)
button_frame.grid(row=3, column=0, columnspan=2, pady=10)
ttk.Button(button_frame, text="删除选中", command=self.delete_record).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="刷新列表", command=self.refresh_display).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="导出数据", command=self.export_data).pack(side=tk.LEFT, padx=5)
# 初始化显示
self.refresh_display()
# 配置grid权重
self.root.columnconfigure(0, weight=1)
self.root.rowconfigure(0, weight=1)
main_frame.columnconfigure(0, weight=1)
main_frame.rowconfigure(2, weight=1)
def add_record(self):
try:
amount = float(self.amount_var.get())
type_ = self.type_var.get()
category = self.category_var.get()
note = self.note_var.get()
if amount <= 0:
messagebox.showerror("错误", "金额必须大于0")
return
if not category:
messagebox.showerror("错误", "请选择类别")
return
record = {
"id": len(self.records) + 1,
"type": type_,
"amount": amount,
"category": category,
"note": note,
"date": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
self.records.append(record)
self.save_records()
self.refresh_display()
# 清空输入
self.amount_var.set("")
self.category_var.set("")
self.note_var.set("")
messagebox.showinfo("成功", f"{type_} ¥{amount:.2f} 记录成功!")
except ValueError:
messagebox.showerror("错误", "请输入有效的金额")
def refresh_display(self):
# 清空表格
for item in self.tree.get_children():
self.tree.delete(item)
# 计算统计
total_income = sum(r["amount"] for r in self.records if r["type"] == "收入")
total_expense = sum(r["amount"] for r in self.records if r["type"] == "支出")
balance = total_income - total_expense
# 更新统计信息
self.stats_labels["total_income"].config(text=f"¥{total_income:.2f}")
self.stats_labels["total_expense"].config(text=f"¥{total_expense:.2f}")
self.stats_labels["balance"].config(text=f"¥{balance:.2f}")
# 添加记录到表格
for record in reversed(self.records[-100:]): # 显示最近100条
self.tree.insert("", "end", values=(
record["date"][:16],
record["type"],
f"¥{record['amount']:.2f}",
record["category"],
record["note"]
))
def delete_record(self):
selected = self.tree.selection()
if not selected:
messagebox.showwarning("警告", "请选择要删除的记录")
return
if messagebox.askyesno("确认", "确定删除选中的记录吗?"):
# 获取选中的记录索引
for item in selected:
values = self.tree.item(item)["values"]
# 查找匹配的记录并删除
for record in self.records[:]:
if (record["date"][:16] == values[0] and
record["type"] == values[1] and
f"¥{record['amount']:.2f}" == values[2]):
self.records.remove(record)
break
self.save_records()
self.refresh_display()
messagebox.showinfo("成功", "记录已删除")
def export_data(self):
if not self.records:
messagebox.showwarning("警告", "没有可导出的数据")
return
filename = f"accounting_export_{datetime.now().strftime('%Y%m%d_%H%M%S')}.json"
with open(filename, 'w', encoding='utf-8') as f:
json.dump(self.records, f, ensure_ascii=False, indent=2)
messagebox.showinfo("成功", f"数据已导出到 {filename}")
if __name__ == "__main__":
root = tk.Tk()
app = AccountingApp(root)
root.mainloop()
使用建议
-
选择哪个版本?
- 如果只是简单用用,方案一就够
- 想要更多功能,用方案二
- 想要图形界面,用方案三
-
数据存储
- 所有方案都使用JSON文件存储
- 可以手动编辑JSON文件
- 建议定期备份数据文件
-
扩展功能
- 可以添加数据库支持(SQLite)
- 可以添加图表显示
- 可以添加预算管理功能
- 可以添加报表导出功能
-
运行方式
- 保存为
.py文件后直接运行 - 方案三需要安装tkinter(Python自带)
- 保存为
需要我帮你进一步定制某个版本,或者添加特定功能吗?
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播