TCX1002 | Python Midterm Cheatsheet (Weeks 1-4)

Personal Python cheatsheet for NUS TCX1002 midterm — only the stuff I forget or haven't drilled

for the full notebook with deeper explanations, see my TCX1002 Notebook.


Mistakes

map/sort/round/split

 1map(fn, iter)                    # NO key=
 2sorted(data, key=lambda x: ...)  # HAS key=
 3
 4round(2.5)  # 2 ← NOT 3!  round(3.5) → 4  (banker's rounding)
 5# need "always up"? → math.ceil()
 6
 7"".split(" ")   # [""] ← NOT []!
 8"".split()      # []  ← 无参数 = 空 list
 9
10sorted(lst)     # returns NEW list
11lst.sort()      # returns None, modifies in-place

Mutable Default

 1def append_to(item, target=[]):
 2    target.append(item)
 3    return target
 4
 5a = append_to(1)   # [1]
 6b = append_to(2)   # [1, 2] ← 不是 [2]!
 7a is b              # True ← 同一个 list!
 8
 9# ✅ FIX:
10def append_to(item, target=None):
11    if target is None:
12        target = []
13    target.append(item)
14    return target

= vs +=

1y = x           # alias
2y = y + [6]     # ✅ 新对象,x 不变
3y += [6]        # ❌ in-place,x 也变!
4y.extend([6])   # ❌ in-place,x 也变!

[[x]] * n 共享引用

 1[[0]] * 3       # [[0], [0], [0]] — 3个ref指向同一个[0]
 2[[0] * 3]       # [[0, 0, 0]]     — 1个list包含3个0
 3[0] * 3         # [0, 0, 0]       — int是immutable,没问题
 4
 5# ❌ 共享引用
 6a = [[0]] * 3
 7a[0].append(1)  # [[0,1], [0,1], [0,1]] ← 全变!
 8
 9# ✅ FIX: comprehension
10a = [[0] for _ in range(3)]  # 3个独立list
11
12# 安全创建 1D / 2D / 3D
13a = [0] * 5                                           # 1D
14b = [[0] * 4 for _ in range(3)]                       # 2D (3×4)
15c = [[[0] * 4 for _ in range(3)] for _ in range(2)]   # 3D (2×3×4)

Mutation During Iteration

1nums = [1, 2, 3, 4, 5]
2for n in nums:
3    if n % 2 == 0:
4        nums.remove(n)
5# for 底层用 index!remove 后 list 左移,下一个被跳过
6
7# ✅ FIX: comprehension
8nums = [n for n in nums if n % 2 != 0]

UnboundLocalError

1x = 10
2def bar():
3    x = foo(x)   # Python 编译时看到 x=... → 整个函数 x 是 local
4    return x      # foo(x) 读 local x,但还没赋值 → boom
5
6# ✅ FIX: 换变量名
7def bar():
8    y = foo(x)   # x 没被赋值,读 global
9    return y
Keyword用途
global x用模块级的 x
nonlocal x用外层函数的 x(嵌套函数)

Truthiness

1bool("")     # False  — 空 string
2bool("0")    # True!  — 非空 string(内容不管)
3bool([0])    # True!  — 非空 list(内容不管)
4bool(0)      # False  — 零
5bool(None)   # False
6
7# 规则:空容器/0/None/False = falsy,其他全 truthy
8# filter(None, iter) = 用 truthiness 过滤
9filter(None, [0, "", None, 1, "hello", [], False])  # → [1, "hello"]

Shallow Copy

1a = [[1,2], [3,4]]
2b = a[:]          # shallow copy — 外层新,内层共享
3b[0].append(5)
4# a = [[1,2,5], [3,4]]  ← a 也变了!
5
6# ✅ FIX: 手动 deep copy(copy 模块不能用)
7b = [row[:] for row in a]

extend vs append

1out.append([1,2])  # [..., [1,2]]  ← 整个 list 当一个元素
2out.extend([1,2])  # [..., 1, 2]   ← 逐个加入

Other

1[1,2] == [1,2]   # True (content)
2[1,2] is [1,2]   # False (identity)
3# is 只用于: x is None
4
5for i in range(5): pass
6print(i)  # 4 — loop var 不会消失

Built-in Methods

 1# STRING
 2"hello world".split()            # ['hello', 'world'] (按空白切)
 3"a,b,c".split(",")              # ['a', 'b', 'c'] (按指定切)
 4"  hello  ".strip()              # 'hello' (去两端空白)
 5"  hello  ".lstrip()             # 'hello  ' (去左)
 6"  hello  ".rstrip()             # '  hello' (去右)
 7"hello world".replace("world", "python")  # 'hello python'
 8", ".join(["a", "b", "c"])       # 'a, b, c' (list → str)
 9"hello".upper()                  # 'HELLO'
10"HELLO".lower()                  # 'hello'
11"hello world".title()            # 'Hello World'
12"hello".capitalize()             # 'Hello' (只首字母)
13"hello".startswith("he")         # True
14"file.py".endswith(".py")        # True
15"abcabc".count("a")             # 2
16"hello".find("ll")              # 2 (index, 没找到返回 -1)
17
18# str.isXXX — 全部字符都要满足才 True, 空字符串返回 False
19"123".isdigit()                  # True
20"abc".isalpha()                  # True
21"abc123".isalnum()               # True (字母或数字)
22"ABC".isupper()                  # True
23"abc".islower()                  # True
24
25# BUILTINS
26len(x)                           # 长度 (str, list, dict, set)
27abs(-5)                          # 5
28round(2.5)                       # 2 ← banker's rounding! (见 Mistakes)
29sorted(lst, reverse=True)        # 降序 (返回新 list)
30min(lst, key=lambda x: x[1])    # 按第2元素找最小
31max(lst, key=lambda x: x[1])    # 按第2元素找最大
32any(x > 5 for x in lst)         # 有一个满足就 True
33all(x > 0 for x in lst)         # 全部满足才 True
34enumerate(lst)                   # → (0,a), (1,b), (2,c) — for i,v in ...
35list(filter(lambda x: x > 0, [-1, 0, 2, 3]))  # [2, 3]
36ord('A')                         # 65   ord('Z') = 90
37ord('a')                         # 97   ord('z') = 122
38ord('0')                         # 48   ord('9') = 57
39chr(65)                          # 'A'  chr(97) = 'a'
40# ord/chr hacks
41ord('c') - ord('a')              # 2 — 字母→index (a=0, b=1, ...)
42chr(ord('a') + 3)                # 'd' — index→字母
43chr(ord('A') + i)                # 'A','B','C'... — 生成大写序列
44chr((ord(c) - ord('a') + shift) % 26 + ord('a'))  # Caesar cipher shift
45
46# LIST
47lst.insert(1, "x")              # 在 index 1 插入 (in-place)
48lst.pop()                       # 删最后一个并返回
49lst.pop(0)                      # 删 index 0 并返回
50lst.remove("x")                 # 删第一个 "x" (in-place, 没有则 ValueError)
51lst.reverse()                   # in-place, 返回 None! (同 .sort())
52lst.index("x")                  # 第一个 "x" 的 index (没有则 ValueError)
53
54# DICT
55d.get(key, default)             # 没有 key 不报错,返回 default
56d.keys()                        # dict_keys([...])
57d.values()                      # dict_values([...])
58d.items()                       # dict_items([(k,v), ...]) ← for k,v in d.items()
59d.pop("key")                    # 删 key 并返回 value (没有则 KeyError!)
60d.pop("key", None)              # 安全版,没有返回 None
61d.update({"a": 1, "b": 2})     # 批量更新/合并
62
63# dict counting (替代 defaultdict(int))
64counts = {}
65counts[item] = counts.get(item, 0) + 1
66
67# dict grouping (替代 defaultdict(list))
68groups = {}
69groups.setdefault(key, []).append(item)
70
71# dict grouping with set (替代 defaultdict(set))
72groups.setdefault(key, set()).add(item)
73
74# SET
75s.add(x)                        # 加一个元素
76s.discard(x)                    # 删元素 (没有也不报错)
77s.remove(x)                     # 删元素 (没有则 KeyError!)
78a & b                           # intersection (交集)
79a | b                           # union (并集)
80a - b                           # difference (a有b没有)
81a ^ b                           # symmetric diff (只在一边有)
82
83# COMPREHENSION
84[x**2 for x in lst]                      # list comp
85[x for x in lst if x > 0]                # 带条件
86{k: v for k, v in pairs}                 # dict comp
87{x for x in lst}                         # set comp
88[[row[i] for row in matrix] for i in range(n)]  # nested (转置)
89
90# TYPE CHECK (A1Q2 用过)
91type(x) == str                  # True if str
92isinstance(x, (int, float))    # True if int or float (推荐)

Iterators(一次性)

1a = map(lambda x: x**2, [1,2,3])
2list(a)   # [1, 4, 9]
3list(a)   # [] ← 空了!
4
5# 一次性: map, filter, zip, enumerate, 所有 itertools
6# 可重复: range, list, tuple, set, dict
7
8# ✅ 安全做法:马上 list() 包住
9result = list(map(lambda x: x**2, data))

functools + itertools

 1from functools import reduce, partial
 2from itertools import combinations, permutations, chain, product, accumulate
 3
 4# reduce — 一个最终值
 5reduce(lambda acc, x: acc + x, [1,2,3,4])      # 10
 6reduce(lambda acc, x: acc * x, [1,2,3,4])      # 24
 7reduce(lambda acc, x: acc + x, [1,2,3], 100)   # 106 (init=100)
 8
 9# partial — pre-fill args
10add10 = partial(lambda x, y: x + y, 10)
11add10(5)  # 15
12
13combinations([1,2,3], 2)      # [(1,2),(1,3),(2,3)]        C(n,k)
14permutations([1,2,3], 2)      # [(1,2),(1,3),(2,1),...]    P(n,k)
15chain([1,2], [3,4])           # [1,2,3,4]                  flatten
16product([1,2], ['a','b'])     # [(1,'a'),(1,'b'),(2,'a'),(2,'b')]
17accumulate([1,2,3,4])         # [1,3,6,10]                 前缀和
18accumulate([3,1,4,1,5], max)  # [3,3,4,4,5]               running max
返回
reduce一个值 (折叠)
accumulate所有中间值 (前缀)

math

 1import math
 2
 3math.ceil(2.1)       # 3   (always round up)
 4math.floor(2.9)      # 2   (always round down)
 5math.sqrt(16)        # 4.0 (or x ** 0.5)
 6math.log(8, 2)       # 3.0 (log base 2)
 7math.log(math.e)     # 1.0 (natural log)
 8math.factorial(5)    # 120
 9math.gcd(12, 8)      # 4
10math.pi              # 3.14159...
11math.e               # 2.71828...
12math.inf             # infinity (or float('inf'))

datetime

 1from datetime import datetime, date, timedelta
 2
 3# 创建
 4today = date.today()                          # date(2026, 2, 14)
 5now = datetime.now()                          # datetime(2026, 2, 14, 10, 30, 0)
 6d = date(2026, 2, 14)                         # 指定日期
 7dt = datetime(2026, 2, 14, 10, 30)            # 指定日期+时间
 8
 9# 属性
10d.year, d.month, d.day                        # 2026, 2, 14
11dt.hour, dt.minute, dt.second                 # 10, 30, 0
12
13# timedelta — 加减时间
14d + timedelta(days=7)                         # 7天后
15d - timedelta(weeks=2)                        # 2周前
16dt + timedelta(hours=2, minutes=30)           # 可以混用 (⚠️ 要 datetime 不是 date!)
17(date(2026, 3, 1) - date(2026, 2, 14)).days   # 15(差几天)
18
19# 格式化
20dt.strftime("%Y-%m-%d %H:%M")                # '2026-02-14 10:30'
21datetime.strptime("14/02/2026", "%d/%m/%Y")  # str → datetime
22# %Y=年4位  %m=月2位  %d=日2位  %H=时24  %M=分  %S=秒
23
24# 比较 (A1Q2 attendance)
25start = datetime(2025, 1, 1, 19, 0, 0)
26scanned = datetime(2025, 1, 1, 19, 8, 0)
27scanned <= (start + timedelta(minutes=15))   # True → on time
28end = datetime(2025, 1, 1, 21, 0, 0)
29(end - start) / 2                            # 半场时间 (timedelta)

random

 1import random
 2
 3random.randint(1, 10)          # 1到10 的随机整数(包含两端)
 4random.random()                # 0.0 到 1.0 的随机浮点数
 5random.uniform(1.5, 5.5)      # 指定范围的随机浮点数
 6random.choice([1, 2, 3])      # 随机选一个
 7random.sample([1,2,3,4,5], 3) # 随机选3个(不重复,返回 list)
 8random.shuffle(lst)            # in-place 打乱(返回 None!)
 9
10# 可重现
11random.seed(42)                # 设 seed → 每次结果一样

NumPy

List vs NumPy:

操作ListNumPy
a + b拼接 [1,2,3,4]逐元素加 [5,7,9]
a * 3repeat [1,2,1,2,1,2]逐元素乘 [3,6,9]
a > 1TypeErrorbool array [F,T,T]
len(a)元素个数第一维长度
sum(a)总和总和(但用 np.sum 更快)
 1# 同一个任务,List vs NumPy 写法对比:
 2
 3# 每个元素 +10
 4[x + 10 for x in lst]           # List: comprehension
 5arr + 10                         # NumPy: broadcasting
 6
 7# 过滤 >5
 8[x for x in lst if x > 5]       # List: comprehension
 9arr[arr > 5]                     # NumPy: boolean indexing
10
11# 逐元素相乘
12[a*b for a,b in zip(l1, l2)]    # List: zip + comprehension
13arr1 * arr2                      # NumPy: 直接乘
14
15# 互转
16np.array([1,2,3])               # list → numpy
17arr.tolist()                     # numpy → list
 1import numpy as np
 2
 3# 创建
 4np.array([1,2,3])             # from list
 5np.zeros((3,4))               # 3×4 全0
 6np.ones((2,3))                # 2×3 全1
 7np.arange(0, 10, 2)           # [0, 2, 4, 6, 8]
 8np.linspace(0, 1, 5)          # [0, 0.25, 0.5, 0.75, 1.0]
 9
10# shape 操作
11a.shape                        # (3, 4)
12a.reshape(2, 6)                # 改形状(元素总数不变)
13a.flatten()                    # 拉成 1D
14a.T                            # 转置
15
16# axis — 0=行方向(↓列压缩), 1=列方向(→行压缩)
17np.sum(a, axis=0)              # 每列的和
18np.sum(a, axis=1)              # 每行的和
19np.mean(a, axis=0)             # 每列平均
20np.max(a, axis=1)              # 每行最大
21
22# boolean filter
23a[a > 5]
24
25# broadcasting (pairwise) — newaxis 插入维度
26R = a[:, np.newaxis, :]   # (n, 1, d) — 中间插 = Row
27C = a[np.newaxis, :, :]   # (1, n, d) — 前面插 = Column
28D = R - C                  # (n, n, d) — 所有 pair 的差
29# 规则: 从右对齐,1可以拉伸 → (1,3) + (2,1) → (2,3)
30
31# useful ops
32np.where(a > 5)                # 满足条件的 index 数组
33np.argmax(a)                   # 最大值的 index
34np.argsort(a)                  # 排序后的 index 数组
35np.dot(a, b.T)                 # 矩阵点积
36np.linalg.norm(a, axis=1)     # 每行的向量长度 (L2 norm)
37np.outer(a, b)                 # 外积 (n,) × (m,) → (n,m)
38
39# local peaks (T1Q4)
40lefts, currs, rights = x[:-2], x[1:-1], x[2:]
41scale = 1 + threshold
42peaks = np.where((currs > lefts*scale) & (currs > rights*scale))[0] + 1
43
44# pairwise distances (T3Q4)
45manhattan = np.sum(np.abs(D), axis=2)
46euclidean = np.sqrt(np.sum(np.square(D), axis=2))
47
48# cosine distance (T3Q4)
49dot_products = np.dot(a, a.T)
50norms = np.linalg.norm(a, axis=1)
51cosine = 1 - dot_products / np.outer(norms, norms)

Regex

1import re
函数从哪找返回没找到
re.findall(pat, text)所有匹配list of strings[]
re.match(pat, text)开头match objectNone
re.search(pat, text)任意位置(第一个)match objectNone
re.sub(pat, repl, text)全部替换new string原 string
re.split(pat, text)按 pattern 切list of strings[原text]
re.fullmatch(pat, text)整个 stringmatch objectNone
 1# findall — 返回 strings!不是 int
 2re.findall(r'\d+', "age 25, score 99")       # ['25', '99']
 3nums = list(map(int, re.findall(r'\d+', s)))  # 转 int
 4
 5# search — 返回 match object
 6m = re.search(r'(\d+)-(\d+)', "call 123-456 now")
 7m.group(0)   # '123-456'  ← 完整匹配
 8m.group(1)   # '123'      ← 第一个 ()
 9m.group(2)   # '456'      ← 第二个 ()
10
11# ⚠️ match/search 可能返回 None,先检查!
12m = re.search(r'\d+', text)
13if m is not None:
14    print(m.group())
15
16# sub — 替换
17re.sub(r'\d+', 'X', "abc123def456")  # 'abcXdefX'
18re.sub(r'\s+', ' ', "  too  many  ").strip()  # 'too many'
19
20# split — 按多种分隔符
21re.split(r'[,;\s]+', "a, b;c  d")   # ['a', 'b', 'c', 'd']
22
23# greedy vs non-greedy
24re.findall(r'<.+>', '<a><b>')    # ['<a><b>']     ← greedy(尽量多)
25re.findall(r'<.+?>', '<a><b>')   # ['<a>', '<b>']  ← non-greedy(尽量少)
26
27# findall + groups — 有 () 时只返回 group 内容
28re.findall(r'(\d+)-(\d+)', "12-34 56-78")  # [('12','34'), ('56','78')]
29
30# fullmatch — 整个 string 必须匹配
31re.fullmatch(r'[A-Z]{3}\d{4}', "ABC1234")   # match
32re.fullmatch(r'[A-Z]{3}\d{4}', "ABC12345")  # None

常用例子

1re.findall(r'\d{2}/\d{2}/\d{4}', "born 14/02/2026")  # 提取日期
2re.findall(r'\(([^)]+)\)', "f(x) and g(y)")           # 括号内容 → ['x','y']
3re.findall(r'(\w+)=(\w+)', "name=bob age=25")         # key=value pairs

T3Q1 车牌技巧

1r'[A-HJ-NP-Z]'                # A-Z 排除 I 和 O — 多段 range
2r'(?=([A-HJ-NP-Z]{2,3}\d{1,4}[A-Z]))'  # lookahead 找重叠匹配
3m = re.match(r'^([A-Z]+)', "SGP1234A")  # match 提取 prefix
4r'\d{1,4}'                     # {n,m} 精确量词

Regex Notes

 1# 为什么用 r'' (raw string)?
 2r'\d+'     # ✅ backslash 原样传给 regex
 3'\d+'      # ⚠️ Python 先处理 \d → 可能出错
 4# 规则:regex pattern 永远用 r''
 5
 6# \d vs \d+ — Q25 踩过
 7re.findall(r'\d', "abc123")    # ['1', '2', '3']   ← 每个数字
 8re.findall(r'\d+', "abc123")   # ['123']            ← 整个数字串
 9
10# flags
11re.findall(r'hello', "Hello World", re.IGNORECASE)  # ['Hello']
12re.search(r'hello', "Hello", re.I)                  # match (re.I = 缩写)

Pattern 速查

PatternMeaningExample
.any char (except \n)a.c → abc, a1c
\d / \Ddigit / non-digit\d = [0-9]
\w / \Wword char / non-word\w = [a-zA-Z0-9_] (含下划线!)
\s / \Swhitespace / non-wsspace, tab, newline
\bword boundaryr'\bcat\b' 只匹配整个 “cat”,不匹配 “catch”
[A-Z]char range[a-zA-Z] = 所有字母
[^A-Z]NOT (negated class)[^0-9] = 非数字
+ / * / ?1+ / 0+ / 0 or 1\d+ = 一个或多个数字
{n} / {n,m}exactly n / n to m\d{4} = 4位数字
^ / $start / end of string^Hello = 开头是 Hello
(...)capture groupfindall 只返回 group 内容
(?:...)non-capture group分组但不 capture
(?=...) / (?!...)lookahead / neg看前面但不消耗
(?<=...) / (?<!...)lookbehind / neg看后面但不消耗

Good to Know

 1x ** 0.5          # sqrt (no import)
 2float('inf')      # infinity (no import)
 3frozenset({1,2})  # immutable set, can be dict key
 4t = ("A", 1, 2, 3)
 5t[1:]             # (1, 2, 3) — tuple slicing works like list
 6
 7# 常用 1-liners
 8list(dict.fromkeys([1,3,2,1,3]))            # [1,3,2] — 去重保序
 9[x for row in [[1,2],[3,4]] for x in row]   # [1,2,3,4] — 展平 2D
10list(zip(*[[1,2],[3,4]]))                    # [(1,3),(2,4)] — 转置
11sorted([("A",2),("B",1),("C",2)], key=lambda x: (-x[1], x[0]))  # [("A",2),("C",2),("B",1)]
12a, *rest = [1,2,3,4]                        # a=1, rest=[2,3,4]
13[1,2,3][::-1]                               # [3,2,1] — 反转 (不改原 list)

Pre-Submit Checklist

 1EDGE CASES
 2 Empty:          [], "", {}, 0, None
 3 Single:         [1], "a"
 4 All same:       [5,5,5,5]
 5 Negative/zero:  [-1, 0, 1]
 6 Boundaries:     first, last, exactly at condition
 7 Duplicates:     [1,1,2,2]  does spec say unique?
 8 Sorted/reverse: [1,2,3], [3,2,1]
 9
10CORRECTNESS
11 Re-read spec:   am I solving what was ACTUALLY asked?
12 Return type:    list? tuple? string? int? float? match spec
13 Return value:   return X, not print(X)
14 Off-by-one:     range(n) vs range(n+1), < vs <=, [L:R] vs [L:R+1]
15 Mutation:       did I modify the original input? (spec may need it intact)
16 Case:           .lower() if spec says case-insensitive
17
18CLEANUP
19 Remove print(): all debug prints gone
20 Shadowing:      didn't name vars list, dict, sum, max, min, type, id
21 Imports:        all needed modules imported at top
22 Fn signature:   matches spec exactly (name, params, defaults)

comments powered by Disqus

Recent Updates

See all →