導入 你將會學到什麼?
在真實的程式開發中,資料往往不是「直接在程式內寫死」,而是儲存在不同的檔案之中,例如:
- 文字檔案:逐行記錄日誌、留言、清單、設定。
- CSV:用定界符號把資料分成欄,常見於成績表、統計表、匯出資料。
- JSON:用結構化方式保存資料,適合題庫、設定、清單、物件資料。
本章以「輸入-處理-輸出周期」為主線:先從檔案讀入資料(輸入),再用程式整理與計算(處理),最後輸出成新的檔案或報告(輸出)。
課題 1 檔案與資料格式:文字檔案、CSV、JSON
重點
- 文字檔案以「字元」為單位保存內容;讀取後通常以「字串」處理。
- CSV 以「定界符號」分隔欄位,最常見的定界符號是逗號。
- JSON 以結構化方式保存資料,適合表示巢狀資料(例如清單內再包含清單)。
- 同一份資料可以用不同格式保存;選擇格式時要考慮可讀性、可移植性與處理難度。
教學:在 Python 寫入文字檔案(建立示例資料)
寫入文字檔案的基本流程是:以 with open(...) 開啟檔案(常用 w 覆蓋寫入)、指定 encoding="utf-8",再逐行寫入並自行加入換行符號 \\n。
lines = ["Amy 78", "Ben 92", "Cathy 85"]
with open("scores.txt", "w", encoding="utf-8") as f:
for line in lines:
f.write(line + "\n")
定義
- 文字檔案:以「字元」保存內容,常見副檔名如
.txt。讀入後得到「字串」。 - CSV:以「定界符號」分隔欄位的文字檔案,常見副檔名
.csv。 - JSON:以結構化語法保存資料的文字檔案,常見副檔名
.json。
原理/運作
電腦讀入文字檔案後,看到的只是連續的字元。若要把資料拆成「欄」與「列」,就需要清楚的規則:
- CSV:用定界符號把每一行拆成多個欄位(欄)。
- JSON:用括號與符號描述資料的層次(例如清單、配對資料)。
規則越清楚,程式越容易「正確解析」;反之就容易出現「資料對不上欄」或「讀錯結構」的問題。
例子
假設有三位同學的姓名與分數:
文字檔案(較自由)
Amy 78 Ben 92 Cathy 85
CSV(用定界符號分隔)
name,score Amy,78 Ben,92 Cathy,85
JSON(結構化)
[
{"name": "Amy", "score": 78},
{"name": "Ben", "score": 92},
{"name": "Cathy", "score": 85}
]
比較
- 文字檔案:適合日誌、備忘、簡單清單;但格式不固定時,程式要自己定規則。
- CSV:適合表格資料(欄與列清晰);人手檢視方便;但巢狀資料較難表示。
- JSON:適合巢狀與複雜資料(例如題庫、設定);但人手編輯要留意語法。
常見錯誤
- 定界符號混亂:同一檔案部分行用逗號、部分行用分號,會令欄位數量不一致。
- CSV 內容含逗號:例如姓名或備註本身有逗號,若沒有用引號包住,解析會錯位。
- JSON 語法錯誤:常見是漏了逗號、括號不對稱、或使用了不合規的引號。
- 編碼不一致:讀入時若編碼選擇不當,可能看到亂碼或出現解碼錯誤。
當你面對一個「資料檔案」,第一步不是立即寫程式,而是先判斷資料的結構:是自由文字?是表格?還是有巢狀的欄位?結構越清晰,你寫出的算法就越簡潔,也更不容易出錯。
文字檔案最彈性,但也最容易「規則不一」。CSV 對表格非常友好,適合快速整理與統計。JSON 則適合保存更複雜的資料,例如「題目」包含「選項陣列」、「答案」與「解釋」等多層資料。
在本章的後續課題,你會先學會如何讀寫文字檔案,再逐步把讀入的內容轉成「陣列」或其他資料結構,最後輸出成你需要的格式。
為何應從文字檔案讀取資料?
- 資料重用:同一批資料可在不同程式或多次執行中重複使用,避免每次重新輸入。
- 準確性:先把資料整理在檔案內,可降低人手輸入造成的錯字、漏輸或格式不一致。
- 自動化:面對大量資料(例如全班 30 位同學的中英數學成績),以檔案輸入更適合做批次統計、篩選與輸出報表。
Python 練習
以下練習提供「檔案檢視器」,以左右兩欄顯示文本檔案原本與目前內容。你可直接在右欄修改檔案內容,再執行程式觀察結果;如需還原,請按「重設文本檔案」。
課題 2 讀取文字檔案:逐行讀取與資料清洗
重點
open()用於打開檔案;常用模式是r(讀取)。- 使用
with語句可確保檔案在使用後自動關閉,減少錯誤。 read()、readline()、readlines()的行為不同:要按需要選擇。- 讀入後通常需要清洗:移除換行、忽略空行、去除多餘空白。
教學:在 Python 寫入文字檔案(輸出清洗後的結果)
讀取檔案後通常要清洗資料(例如去除空白與空行)。最簡潔的做法是「邊讀邊寫」:讀入一行就清洗一行,並立即寫到新檔案。
with open("raw.txt", "r", encoding="utf-8") as fin, \
open("clean.txt", "w", encoding="utf-8") as fout:
for line in fin:
s = line.strip()
if s:
fout.write(s + "\n")
定義
open() 會回傳一個「檔案物件」,讓你能讀取或寫入檔案內容。
open(path, mode, encoding):path是檔案路徑,mode是模式,encoding是編碼。- 最常用模式:
r(讀取)、w(寫入覆蓋)、a(附加寫入)。
原理/運作
若你手動打開檔案後忘記關閉,可能造成:
- 檔案仍被佔用,其他程式無法正常存取。
- 資料尚未完整寫入(緩衝尚未刷新)。
with open(...) 會在區塊結束時自動關閉檔案,因此較安全、較清晰。
with open("data.txt", "r", encoding="utf-8") as f:
text = f.read()
# 離開區塊後,檔案會自動關閉
例子
read():一次讀入整個檔案
with open("data.txt", "r", encoding="utf-8") as f:
text = f.read()
readline():一次讀一行
with open("data.txt", "r", encoding="utf-8") as f:
line = f.readline()
for 循環:逐行讀取(常用)
with open("data.txt", "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if line:
print(line)
比較
- read():檔案不大時最方便;但大檔案會佔用較多記憶體。
- readline():適合只需要第一行或逐行控制;但通常會配合循環使用。
- 逐行(for line in f):最省記憶體,適合大檔案,也便於即時清洗資料。
常見錯誤
- 忘記去除換行:讀入每行時通常包含
\\n,會影響比較與輸出格式。 - 把空行當資料:沒有忽略空行會令欄位解析出現空值。
- 忽略編碼:當檔案含有中文時,沒有指定
encoding可能導致解碼錯誤。
處理文字檔案時,最常見的資料單位是「一行」。一行可能代表一條記錄(例如一位同學),也可能代表一個設定(例如 theme=dark)。因此,逐行讀取通常最自然:你可以在每次讀到一行時立即清洗與解析。
在讀入資料之後,請先把「非資料」清走,例如多餘空白、換行、空行,然後再把內容轉成你需要的資料結構,例如把每行拆成欄位,再放入陣列。這樣做的好處是:後面的計算與輸出會更穩定,較少出現「資料長度不一致」的錯誤。
良好的讀取策略也與檔案大小有關。小檔案用 read() 可以快速完成;大檔案建議逐行處理,讓程式保持流暢並降低記憶體壓力。
Python 練習:開啟檔案與讀取方法
本節會透過多個練習,讓你比較 read()、readline() 與 readlines() 在「文字檔案串流(text file stream)」中的行為差異。
課題 3 檔案開啟模式(WAX):w/a/x 的用途與差異
重點
- 常用的三種文字檔案開啟模式:
w(Write,覆寫寫入)、a(Append,附加寫入)、x(eXclusive create,只在檔案不存在時建立)。 write()只接受字串;寫入數字前通常要先轉換成字串。- 控制換行很重要:文字檔案通常以
\\n分隔每一行。 - 輸出檔案是「讓結果可保存、可分享、可再次處理」的關鍵一步。
教學:WAX 模式快速比較(w 覆寫、a 附加、x 建立新檔)
選擇正確的開啟模式非常重要:
w:清空舊內容後再寫入,適合「重新生成」一份完整報告。a:在檔案末端附加內容,適合日誌或逐次追加紀錄。x:只在檔案不存在時建立新檔;若已存在會報錯,用於防止覆蓋舊資料。
# w:覆寫(會清空原內容)
with open("report.txt", "w", encoding="utf-8") as f:
f.write("班別:3A\n")
f.write("平均分:78.5\n")
# a:附加(保留原內容,從檔尾加入)
with open("log.txt", "a", encoding="utf-8") as f:
f.write("2026-01-08 18:30 完成統計\n")
# x:建立新檔(已存在會報錯,避免覆蓋)
try:
with open("new_report.txt", "x", encoding="utf-8") as f:
f.write("第一次建立成功\n")
except FileExistsError:
print("檔案已存在:請改用 w 或 a")
print(..., file=f);但若要嚴格控制格式(例如 CSV),建議使用 write()。定義
w:寫入(Write)。若檔案已存在,會先清空再寫入。a:附加(Append)。在檔案末尾追加內容,不會清空原有內容。x:建立新檔(eXclusive create)。只在檔案不存在時建立;若已存在會報錯(FileExistsError)。
a;要重新生成一份完整報告就用 w;要避免覆蓋舊檔就用 x。原理/運作
write() 會把字串原封不動寫入檔案,所以:
- 要自己加上
\\n才會換行。 - 若你連續寫多段內容,最終檔案的排版會完全依賴你寫入的字元。
with open("report.txt", "w", encoding="utf-8") as f:
f.write("班別:3A\\n")
f.write("平均分:78.5\\n")
例子
除了 write(),你也可以用 print(..., file=f):
with open("report.txt", "w", encoding="utf-8") as f:
print("班別:3A", file=f)
print("平均分:78.5", file=f)
print() 會自動加換行,對文字報告很方便。比較
- write():更精準控制內容;適合要固定格式(例如 CSV)。
- print(file=...):更方便寫多行文字;適合報告或日誌。
常見錯誤
- 用錯模式導致覆蓋:本來要保留舊內容,卻使用
w,令資料被清空。 - 直接寫入數字:
write(10)會出錯,需先轉換成字串,例如write(str(10))。 - 換行不一致:忘記加
\\n,結果所有內容黏在同一行。
當你完成資料整理與計算之後,若只把結果顯示在畫面上,資料很容易在關閉程式後消失。把結果輸出成檔案,等於為你的處理流程加上「可保存」與「可追蹤」的能力。
寫入時,最需要小心的是檔案模式:w 會覆蓋舊內容,適合生成全新報告;a 會附加內容,適合記錄日誌或追加紀錄;x 只在檔案不存在時建立新檔,用於避免不小心覆蓋舊資料。只要模式選對,你的輸出就會更符合需要。
另外,輸出格式應該「為下一步服務」。例如你要把報告再匯入試算表,就用 CSV;若要讓另一個程式讀取,就考慮 JSON;若只求易讀,就輸出成文字報告。
Python 練習:WAX 模式(先 w,再 a,再 x)
本部分練習會依序安排:w 示範 → w 練習 → a 示範 → a 練習 → x 示範 → x 練習。建議你先執行示範題觀察效果,再在練習題中補上少量程式碼,完成同類型操作。
課題 4 CSV 處理:由文字到表格資料
重點
- CSV 以「定界符號」分隔欄位;最常見是逗號,但也可能是分號或 Tab。
- 處理 CSV 的核心是:逐行讀取 → 按定界符號拆分 → 把每欄轉成合適的資料類型。
- 處理數值時常需要「轉換數據類型」,例如把字串轉為整數。
- 完成解析後,可進一步做統計(例如平均數),這類運算常可視為「集合函數」。
教學:在 Python 寫入文字檔案(輸出 CSV)
輸出 CSV 時建議使用 csv 模組,並在開檔時加入 newline=""(特別是在 Windows)以避免多餘空行。
import csv
rows = [
["name", "score"],
["Amy", 78],
["Ben", 92],
]
with open("scores.csv", "w", encoding="utf-8", newline="") as f:
w = csv.writer(f)
w.writerows(rows)
定義
- 欄(field):表格中的一格資料,例如「姓名」或「分數」。
- 定界符號(delimiter):用來分隔欄位的符號,例如逗號
,。
原理/運作
解析 CSV 的基本流程:
- 讀取每一行(通常跳過表頭)。
- 用定界符號拆分成「欄位陣列」。
- 把需要計算的欄位做「轉換數據類型」,例如
int()。
line = "Amy,78"
parts = line.split(",") # parts = ["Amy", "78"]
name = parts[0]
score = int(parts[1])
例子
scores = []
with open("marks.csv", "r", encoding="utf-8") as f:
next(f) # 跳過表頭
for line in f:
parts = line.strip().split(",")
scores.append(int(parts[1]))
avg = sum(scores) / len(scores)
print(avg)
比較
- 自己 split:概念直觀,適合入門;但遇到「資料本身含逗號」會較棘手。
- csv 模組:更符合 CSV 規格(處理引號、逗號等);適合正式程式。
常見錯誤
- 欄位數不一致:有些行少了欄位,拆分後長度不足會造成索引錯誤。
- 空值:例如分數是空字串,
int('')會出錯;需先做有效性檢驗。 - 忘記跳過表頭:把
score當成數字轉換會出錯。
CSV 的優勢在於它非常像表格:每行是一筆記錄,每個欄位都對應到清楚的意義。你可以先用最基本的拆分方式理解其運作,然後再進一步使用標準模組處理更複雜的情況。
當你把 CSV 解析成陣列或其他資料結構後,就可以把「檔案」問題轉成「資料結構」問題:例如對分數做排序法、找最高最低、計算平均數或中位數。這也是把資料處理流程變得可重用的關鍵。
真正困難的部分往往不是公式,而是資料品質。你需要在解析時加入有效性檢驗:例如欄位是否足夠、分數是否為數字、是否在合理範圍。這會在課題 6 進一步討論。
Python 練習:資料處理(搜尋/分拆/替換/篩選)
本節練習會使用文字處理技巧(例如 split、replace、條件篩選),並示範若要把處理結果寫回檔案,必須以合適模式重新開啟檔案。
課題 5 JSON 處理:結構化資料的讀寫
重點
- JSON 適合保存結構化資料,例如「題目清單」或「設定」。
- 常用函數:
json.load()/json.dump()(讀寫檔案),以及json.loads()/json.dumps()(讀寫字串)。 - JSON 讀入後常會變成「陣列」與「鍵值配對」的組合,再用算法逐步處理。
- 輸出 JSON 時可加
indent令檔案更易讀。
教學:在 Python 寫入文字檔案(輸出 JSON)
輸出 JSON 時可用 json.dump() 直接寫入檔案,並配合 ensure_ascii=False 保留中文、indent 令檔案更易讀。
import json
data = [
{"name": "Amy", "score": 78},
{"name": "Ben", "score": 92},
]
with open("scores.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
json.dumps() 先取得字串,再按需要寫入檔案。定義
JSON 主要由兩種結構組成:
- 陣列:用
[ ]表示一串項目。 - 鍵值配對:用
{ }表示「鍵 → 值」。
[
{"name": "Amy", "score": 78},
{"name": "Ben", "score": 92}
]
原理/運作
json.load(f):從檔案物件讀入 JSON。json.dump(obj, f):把資料寫入檔案物件(輸出 JSON)。json.loads(text):從字串讀入 JSON。json.dumps(obj):把資料轉成 JSON 字串。
例子
import json, random
with open("questions.json", "r", encoding="utf-8") as f:
bank = json.load(f) # bank 通常是陣列
q = random.choice(bank)
print(q["question"])
比較
- CSV:表格資料強;但多層結構較難表達。
- JSON:多層結構強;適合題庫、設定、巢狀資料。
常見錯誤
- 漏逗號 或 多逗號:JSON 語法非常嚴格。
- 引號問題:JSON 的字串通常使用雙引號。
- 型態錯配:把字串當數字或把數字當字串,會影響比較與計算。
JSON 的價值在於「結構」。當資料不再只是兩欄三欄的表格,而是每筆資料都有多個屬性,甚至包含另一個陣列(例如選項列表),JSON 會比 CSV 更容易表達,也更容易擴充。
在處理 JSON 時,做法往往是:先把 JSON 讀入成資料結構,再使用算法逐步操作,例如遍歷陣列、用鍵取值、篩選、統計與重組。當你能熟練這套流程,就能把「題庫小測」、「設定檔」、「簡易資料庫」等需求快速實作。
輸出 JSON 時,建議使用縮排(例如 indent=2)以提升可讀性。這不會影響程式讀取,但會令你和同學在檢查檔案時更容易找到問題。
Python 練習:讀寫 JSON(查詢/更新/刪除紀錄)
你將把 JSON 檔案讀入為 list / dict,完成查詢統計、更新指定 id,以及刪除指定紀錄後寫回檔案。
課題 6 有效性檢驗與異常處理:讓程式更可靠
重點
- 資料不一定乾淨:可能缺欄、空值、亂碼、超出範圍,因此要做「有效性檢驗」。
- 「異常處理」用於處理不可預期情況,例如檔案不存在或轉換數據類型失敗。
- 常見做法是:先用
if做基本檢查,再以try/except捕捉例外。 - 錯誤訊息要「有用」:能指出哪一行、哪一欄出錯,並提供合理的處理策略。
教學:在 Python 寫入文字檔案(錯誤記錄 log)
可靠的程式會把錯誤「說清楚、記下來」。遇到例外時可把錯誤訊息附加寫入 log 檔,方便日後追查與修正資料。
try:
score = int("abc") # 示意:可能失敗的轉型
except ValueError as e:
with open("error.log", "a", encoding="utf-8") as f:
f.write(f"[ValueError] {e}\n")
定義
- 有效性檢驗(validation):在使用資料前先檢查是否符合規則,例如分數是否為 0–100 的整數。
- 異常處理(exception handling):用程式結構處理執行期間出現的例外情況,例如檔案不存在。
原理/運作
建議只捕捉「你能合理處理」的錯誤。例如:
FileNotFoundError:提示檔案路徑或檔名是否正確。ValueError:提示某欄位不是數字,並記錄出錯位置。
try:
score = int(text)
except ValueError:
score = None
例子
errors = []
scores = []
for idx, line in enumerate(lines, start=1):
parts = line.strip().split(",")
if len(parts) < 2:
errors.append(f"第 {idx} 行:欄位不足")
continue
name = parts[0].strip()
try:
score = int(parts[1])
except ValueError:
errors.append(f"第 {idx} 行:分數不是整數")
continue
if not (0 <= score <= 100):
errors.append(f"第 {idx} 行:分數超出範圍")
continue
scores.append(score)
比較
- if 檢查:適合檢查「可預先判斷」的條件,例如欄位數量、是否空字串。
- try/except:適合捕捉「執行時才知道」的錯誤,例如轉換數據類型失敗。
常見錯誤
- 只輸出「出錯了」:沒有指出位置與原因,難以修正資料。
- 把錯誤直接忽略:跳過錯誤可以,但最好同時記錄錯誤清單。
- 把例外當常態:例如每一行都靠 try/except 來控制流程,會令邏輯混亂。
現實世界的資料往往不完美。即使同一份表格,也可能出現漏填、手誤、格式不一致等問題。因此,寫出「能跑」的程式只是第一步;更重要的是寫出「遇到壞資料也不會崩潰」的程式。
有效性檢驗的重點是先定規則:例如分數一定是整數、範圍是 0–100、每行至少兩欄。當規則清楚,你就能在讀入後立刻檢查,並決定如何處理:跳過、修正、或終止。
異常處理則是在程式執行中提供「安全網」。遇到檔案不存在、轉換失敗等情況時,程式不應直接終止,而應給出清晰訊息,讓使用者知道下一步怎樣做。
Python 練習:資料驗證與例外處理
本節練習會加入不完整或不合理資料,讓你練習以 try...except 處理錯誤,並以規則驗證後再寫入檔案。
課題 7 迷你專題:成績報告(CSV → 統計 → 輸出)
重點
- 把成績 CSV 讀入後轉成資料結構(例如陣列),再進行統計與排序法。
- 輸出時要考慮用途:給人閱讀可用文字報告;給軟件處理可用 CSV 或 JSON。
- 統計運算(例如平均數、最高分)可視為常見的「集合函數」應用。
- 專題重點是建立一條可重用的資料流程,而非只完成一次性的計算。
教學:在 Python 寫入文字檔案(輸出成績報告)
完成統計後可把結果輸出成報告檔。建議在報告中清楚列出來源、時間與統計方法,並以固定格式逐行寫入。
from datetime import date
with open("report.txt", "w", encoding="utf-8") as f:
f.write(f"生成日期:{date.today()}\n")
f.write("班別:3A\n")
f.write("平均分:78.5\n")
f.write("最高分:96\n")
定義
本專題把整個工作拆成 3 個清晰步驟:
- 讀入:由
marks.csv讀取資料。 - 處理:轉成資料結構,計算統計量並整理結果。
- 輸出:產生
report.txt或report.csv。
原理/運作
在計算前先做兩件事:
- 把每行拆成欄位,並把分數轉成數字(轉換數據類型)。
- 做有效性檢驗:欄位數量、分數範圍、空值。
完成後再做統計(平均數、最高、最低),程式會更穩定。
例子
讀入 marks.csv 跳過表頭 對每一行: 拆分欄位 把分數轉成整數 若分數無效,記錄錯誤並跳過 保存(姓名, 分數) 計算平均數、最高分、最低分 輸出 report.txt(包含統計與錯誤清單)
# 示意程式(重點是流程)
rows = []
errors = []
with open("marks.csv", "r", encoding="utf-8") as f:
next(f)
for idx, line in enumerate(f, start=2):
parts = line.strip().split(",")
if len(parts) < 2:
errors.append(f"第 {idx} 行:欄位不足")
continue
name = parts[0].strip()
try:
score = int(parts[1])
except ValueError:
errors.append(f"第 {idx} 行:分數不是整數")
continue
if not (0 <= score <= 100):
errors.append(f"第 {idx} 行:分數超出範圍")
continue
rows.append((name, score))
scores = [s for _, s in rows]
avg = sum(scores) / len(scores) if scores else 0
with open("report.txt", "w", encoding="utf-8") as out:
out.write(f"人數:{len(scores)}\\n")
out.write(f"平均分:{avg:.1f}\\n")
out.write(f"最高分:{max(scores) if scores else 0}\\n")
out.write(f"最低分:{min(scores) if scores else 0}\\n")
if errors:
out.write(\"\\n錯誤清單:\\n\")
for e in errors:
out.write(e + \"\\n\")
比較
- TXT:最易讀,適合報告;但再處理較麻煩。
- CSV:適合匯入試算表做分析;欄位固定,兼容性高。
- JSON:適合保存更多細節(例如每位同學的等級與備註),亦方便程式再次讀取。
常見錯誤
- 分母為 0:若沒有有效分數,
len(scores)會是 0,需先處理。 - 未處理錯誤資料:一筆壞資料就令整個程式崩潰。
- 輸出格式不一致:同一欄位在不同地方用不同格式,會令檢查與匯入更困難。
專題的目標不是把所有功能一次做完,而是建立一條「可持續擴充」的資料流程。先做到最基本的版本:讀入、計算平均分、輸出報告;然後再加入錯誤清單、等級判斷、排序法、分佈統計等功能。
當你能把流程拆成清晰的步驟,你就能很自然地把每一步變成子程式,令程式更易測試與除錯,也更容易與同學分工。
下一課題會把 JSON 題庫應用在「題庫小測」專題,並示範如何把作答結果輸出為檔案,形成一個完整的輸入-處理-輸出周期。
Python 練習:正確更新檔案內容
你將練習「讀取 → 修改 → 寫回」的正確流程,並理解為何不建議直接手動改動文字檔案(容易破壞格式、難以追蹤與重現)。
課題 8 迷你專題:題庫小測(JSON → 出題 → 輸出成績)
重點
- 題庫可以用 JSON 保存:題目、選項陣列、答案與解釋。
- 出題流程:讀入題庫 → 隨機抽題 → 記錄作答 → 計分。
- 把結果輸出成 CSV 可方便匯入試算表;輸出成 JSON 則方便程式再次處理。
- 專題重點是「資料結構設計」:你要決定題庫與作答紀錄如何表示。
教學:在 Python 寫入文字檔案(記錄作答結果)
題庫練習常需要把作答紀錄輸出,便於分析與重溫。最簡單的方法是把每次作答寫成 CSV 的一行並使用 a 模式附加。
from datetime import datetime
qid = "cp8_q01"
choice = "B"
is_correct = True
ts = datetime.now().isoformat(timespec="seconds")
line = f"{ts},{qid},{choice},{int(is_correct)}\n"
with open("attempts.csv", "a", encoding="utf-8") as f:
f.write(line)
定義
一個常見的題庫結構(每題是一個鍵值配對物件):
question:題目文字choices:選項陣列answer:正確答案(可用索引或文字)explanation:解釋(可選)
原理/運作
輸出作答結果有三個主要用途:
- 保存:關閉程式後仍可查看。
- 分析:統計常錯題目、計算平均分、找出學習盲點。
- 分享:把結果交給老師或同學共同檢視。
例子
讀入 questions.json 隨機抽出 5 題 對每題: 顯示題目與選項 讀入使用者答案 若正確,分數 +1 記錄(題目, 使用者答案, 是否正確) 輸出 result.csv(包含分數與每題結果)
# 示意程式(重點是資料結構)
import json, random
with open("questions.json", "r", encoding="utf-8") as f:
bank = json.load(f)
picked = random.sample(bank, k=5)
records = []
score = 0
for q in picked:
print(q["question"])
for i, c in enumerate(q["choices"], start=1):
print(i, c)
ans = input("你的答案(輸入選項號碼):").strip()
correct = str(q["answer"])
is_ok = (ans == correct)
if is_ok:
score += 1
records.append((q["question"], ans, correct, is_ok))
with open("result.csv", "w", encoding="utf-8") as out:
out.write("question,answer,correct,is_correct\\n")
for r in records:
out.write(f\"{r[0]},{r[1]},{r[2]},{r[3]}\\n\")
out.write(f\"score,{score},5,\\n\")
比較
- CSV:方便匯入試算表做統計;適合固定欄位的結果表。
- JSON:可保存更複雜的作答資料(例如每題的解釋、用時、重試次數)。
常見錯誤
- CSV 內容含逗號:題目或答案含逗號時,需用引號包住或改用 JSON。
- 未統一答案表示:有些題用「索引」,有些用「文字」,會令比對變複雜。
- 忘記保存作答紀錄:只計總分而不存每題結果,會失去分析價值。
題庫小測專題能把你在本章學到的技能串連起來:你需要設計題庫的 JSON 結構,讀入後抽題,運用循環逐題處理,再把作答結果輸出成檔案。整個過程既是算法訓練,也是資料結構訓練。
如果你希望小測更「可用」,可以加入更多欄位,例如作答時間、題目主題、錯題清單,甚至為每題附上提示。當資料保存得越完整,你就越容易從中看見自己的學習進度。
在最後的練習區,你將看到 20 條「偽代碼 → Python」挑戰題。這些題目聚焦於「把文字資料整理成結構」,讓你用程式把概念真正做出來。
Python 練習:綜合應用
本節把前面技巧整合起來,包括讀取/寫入/更新檔案、以及完成後關閉檔案(close)的重要性。
Python 額外練習(20 題)
以下 20 題為本章延伸練習,重點集中在文字檔案(.txt)的讀取(read / readline / readlines)以及寫入模式(w / a / x)。每題都設有「文件檢視器」(左右兩欄:原本/目前),方便你觀察程式執行前後檔案內容的變化。
(可選)練習索引:快速跳到指定題目
載入中…