🎯 本週一句話主線
把「程式可重用」再升級成「可控、可擴充、可除錯」:
例外處理進階 + 字串/資料解析 + 推導式/生成器 + 排序 key + 基礎複雜度。
1) 必考核心觀念(W2 高頻)
1.1 變數作用域:LEGB(常考觀念)
- Local(函式內)
- Enclosing(巢狀函式外層)
- Global(模組層)
- Built-in(內建)
- 修改外層變數:
- nonlocal x(巢狀函式)
- global x(全域)
1.2 可變/不可變(side effect 陷阱)
- 不可變:
int, float, str, tuple - 可變:
list, dict, set - 參數傳遞是「物件參考」:可變物件可能被函式原地修改。
1.3 淺拷貝 vs 深拷貝(常考)
b = a:同一物件(alias)b = a[:]:淺拷貝(只拷第一層)copy.deepcopy(a):深拷貝(含巢狀)
2) 字串/資料解析模板(W2 必考)
2.1 常用字串方法
strip():去頭尾空白split():切分欄位replace():替換startswith():判斷開頭(例如註解行#)
s = line.strip()
parts = s.split(",")
s2 = s.replace(" ", "")
if s.startswith("#"):
continue
2.2 解析 key=value(超高頻)
token = "k=123"
k, v = token.split("=")
v = int(v)
2.3 解析多行資料(像 log / csv / 表格)
records = []
for line in lines:
if not line.strip():
continue
a, b, c = line.strip().split()
records.append((a, int(b), float(c)))
3) 例外處理進階(必考)
3.1 except ... as e + else + finally
try:
x = float(input())
y = 1 / x
except (ValueError, ZeroDivisionError) as e:
print("bad input:", e)
else:
print("ok:", y) # 沒例外才會走
finally:
print("done") # 一定會走(收尾/關檔)
3.2 主動丟例外(題目要求輸入不合法就拒絕)
if x < 0: raise ValueError("x must be non-negative")
4) 推導式 / 生成器(效能 + 可讀性)
4.1 List comprehension
squares = [x*x for x in nums if x % 2 == 0]
4.2 Dict comprehension
m = {name: score for name, score in pairs}
4.3 Generator expression(省記憶體)
total = sum(x*x for x in nums)
4.4 考點:list vs generator
- list:立即生成、可
len()、較吃記憶體 - generator:惰性生成、省記憶體、用過會被消耗
5) 排序與 key(W2 最高頻技能)
5.1 sort() vs sorted()
arr.sort(...):原地排序sorted(arr, ...):回傳新 list
arr.sort(key=lambda x: x[1]) # 依第2欄
brr = sorted(arr, key=lambda x: x[1])
5.2 逆序(由大到小)
arr.sort(key=lambda x: x[1], reverse=True)
5.3 多鍵排序
arr.sort(key=lambda x: (x[1], x[0])) # 先比第2欄,再比第1欄
6) 檔案 I/O(若課堂有帶到,期末更常用)
6.1 讀檔(推薦 with)
with open("data.txt", "r", encoding="utf-8") as f:
lines = f.readlines()
6.2 寫檔
with open("out.txt", "w", encoding="utf-8") as f:
f.write("hello\n")
7) 複雜度直覺(加分點/避免超時)
- 單迴圈:O(n)
- 雙迴圈:O(n²)
- 排序:O(n log n)
- dict/set 查找:平均 O(1)
8) W2 範例(可直接改作業/考題)
範例 1:解析多行 name score,輸出 Top-3(排序 + 例外)
import sys
def parse_line(line):
name, s = line.strip().split()
score = float(s)
return name, score
def solve(lines):
items = []
for line in lines:
if not line.strip():
continue
try:
items.append(parse_line(line))
except ValueError:
continue # 格式錯就跳過(或改成 raise 視題意)
items.sort(key=lambda x: x[1], reverse=True)
return items[:3]
def main():
lines = sys.stdin.read().splitlines()
top3 = solve(lines)
for name, score in top3:
print(name, f"{score:.2f}")
if __name__ == "__main__":
main()
範例 2:淺拷貝陷阱(觀念題常考)
a = [[1, 2], [3, 4]]
b = a[:] # shallow copy
b[0][0] = 999
# a[0][0] 也會變 999
import copy
c = copy.deepcopy(a)
9) 易錯點(扣分熱區)
- 可變物件被函式原地改掉(side effect)
a[:]只能複製第一層,巢狀仍共享split()欄位數不對 → ValueError- 排序忘記
key或reverse - generator 被消耗一次就沒了
- 檔案未用
with/編碼錯誤 - 用 list 線性查找造成超時(應改 dict/set)
10) ✅ 考前 10 分鐘速讀清單(必背 10 條)
try/except/else/finally流程raise ValueError("msg")- list/dict comprehension
sum(x*x for x in nums)(generator)arr.sort(key=lambda x: ...)- 多鍵排序
(x[1], x[0]) - shallow vs deep copy
- dict/set 平均 O(1) 查找
with open(..., encoding="utf-8")- LEGB +
global/nonlocal





















