行動練習:做一個記帳小工具
把前面學到的變數、條件、迴圈、函式、串列和字典全部串起來,一步一步做出一個會把資料存成 CSV 的記帳小工具。
這一堂,你要做出真的能用的東西
前面六堂課,你學了一塊一塊的積木。這一堂要把它們組起來,做一個你明天就能開始用的記帳工具:
- 在終端機輸入類別、項目、金額,記下一筆花費
- 資料存在
expenses.csv,關掉程式再打開,紀錄還在 - 隨時看各類別的小計和總計
完成後大約 60 行(含空行)。別擔心,我們會一段一段來,每一段都是你學過的東西。
先規劃,再寫程式
動手之前,先想清楚兩件事。這也是你之後請 AI 寫程式前,最該先想好的部分。
資料長什麼樣子? 一筆花費是一個字典,所有紀錄是「字典組成的串列」,和上一堂一模一樣:
{"date": "2026-11-07", "category": "餐費", "item": "雞腿便當", "amount": 85}
需要哪些功能? 每個功能各寫一個函式:
| 函式 | 負責的事 |
|---|---|
load_records |
程式開啟時,從 CSV 讀入舊紀錄 |
save_records |
把所有紀錄寫回 CSV |
ask_amount |
問金額,確定是數字(第 5 堂寫過) |
add_record |
記一筆新的花費 |
show_report |
依類別加總並印出報表 |
main |
顯示選單,依照選擇呼叫上面的函式 |
每個方塊都是一個函式,各自只做一件事。
第一步:準備工作
在你的練習資料夾建立 expense.py,最上面先寫:
import csv
from datetime import date
from pathlib import Path
FILE = Path("expenses.csv")
FIELDS = ["date", "category", "item", "amount"]
import 是「借用 Python 內建的工具箱」:csv 負責讀寫 CSV,date 用來拿今天的日期,Path 用來代表一個檔案路徑。
全大寫的變數名稱是一種習慣,意思是「這是設定值,程式執行中不會改它」。
第二步:讀檔與存檔
def load_records():
if not FILE.exists():
return []
with FILE.open(encoding="utf-8-sig", newline="") as f:
records = list(csv.DictReader(f))
for r in records:
r["amount"] = int(r["amount"])
return records
def save_records(records):
with FILE.open("w", encoding="utf-8-sig", newline="") as f:
writer = csv.DictWriter(f, fieldnames=FIELDS)
writer.writeheader()
writer.writerows(records)
幾個新東西,一次說明:
with ... as f:打開檔案,縮排裡的程式跑完後會自動關檔。就算中途出錯也會關好,不會讓檔案卡住。csv.DictReader:把 CSV 的每一列讀成一個字典,鍵就是第一列的欄位名稱。正好是我們要的格式。int(r["amount"]):還記得第 3 堂的坑嗎?從檔案讀出來的東西都是字串,要計算前得轉成數字。"w":寫入模式,會用新內容整個覆蓋舊檔案。
寫到這裡,先別急著往下。這兩個函式還沒被呼叫,執行程式不會有任何反應,這是正常的。
第三步:記一筆和看報表
def ask_amount(question):
while True:
text = input(question)
if text.isdigit():
return int(text)
print("請輸入阿拉伯數字,例如 85")
def add_record(records):
category = input("類別(例如 餐費、交通):")
item = input("項目:")
amount = ask_amount("金額:")
records.append({"date": date.today().isoformat(), "category": category,
"item": item, "amount": amount})
save_records(records)
print("已記下!")
def show_report(records):
if not records:
print("還沒有任何紀錄")
return
by_category = {}
for r in records:
cat = r["category"]
by_category[cat] = by_category.get(cat, 0) + r["amount"]
for cat, subtotal in by_category.items():
print(f"{cat}:{subtotal} 元")
print(f"總計:{sum(by_category.values())} 元")
ask_amount 直接沿用第 5 堂的版本。show_report 的加總邏輯就是第 6 堂的「依類別加總」。.items() 會同時給你每個鍵和值,.values() 只給值。
date.today().isoformat() 會產生像 2026-11-07 這樣的日期字串。每記一筆就馬上存檔,就算你直接關掉視窗,資料也不會遺失。
第四步:選單,把一切串起來
def main():
records = load_records()
print(f"已讀入 {len(records)} 筆紀錄")
while True:
choice = input("\n1 記一筆 2 看報表 q 離開:")
if choice == "1":
add_record(records)
elif choice == "2":
show_report(records)
elif choice == "q":
print("掰掰,明天也要記帳喔!")
break
else:
print("請輸入 1、2 或 q")
main()
break 會立刻跳出 while 迴圈,程式就結束了。字串裡的 \n 代表換行,讓選單前面空一行比較好讀。
把四個步驟的程式依序貼在同一個檔案裡,執行看看:
python expense.py
記幾筆之後,到資料夾裡找到 expenses.csv,用 Excel 或 VS Code 打開,你會看到自己的資料整整齊齊地排好。
卡住了怎麼辦
最常見的三種狀況:
IndentationError:貼上程式時縮排亂掉了。每個def底下的內容都要往右 4 格。NameError: name 'xxx' is not defined:通常是打錯字,或函式的順序不對。main()這一行一定要放在最後面。KeyError: 'amount':CSV 第一列的欄位名稱被改過了。刪掉expenses.csv讓程式重建即可(記帳資料會一起清空,先備份)。
我在做一個 Python 的記帳小工具,執行時出現下面的錯誤。我是初學者,請告訴我:1)這個錯誤是什麼意思;2)最可能是我程式的哪一行出問題;3)怎麼修。請不要整份重寫,只指出要改的地方。
錯誤訊息:(完整貼上)
我的程式:(完整貼上)
「不要整份重寫,只指出要改的地方」這句很重要。這樣你才知道問題出在哪,下次就會自己修。
- 照著四個步驟完成
expense.py,記下你今天真實的 3 筆花費,再用 Excel 打開expenses.csv確認。 - 加一個新功能:選單多一個
3 看最近 5 筆,印出最後 5 筆紀錄的日期、項目和金額。(提示:還記得串列的負數索引嗎?records[-5:]可以拿到最後 5 筆。) - 挑戰:自己先想好怎麼做,再請 Claude 幫你加上「只看本月份」的報表功能。拿到程式後,先讀懂每一行,再執行驗收。
恭喜你完成了這個單元。你已經能讀懂並寫出一支真的派得上用場的程式了。
讀完了嗎?
標記完成後,單元與專案的進度會自動更新(只存在這台裝置的瀏覽器)。
留言與討論
卡關了、有心得,或發現內容需要更新?都歡迎留言。留言使用 GitHub 帳號登入。