CSC108H5: Introduction to Computer Programming
第一次考试复习
知识点复习 · 卷子补充 · 2024 TT1 真题逐题讲
| 按键 | 作用 |
|---|---|
| → / 空格 | 下一步。题目页会先揭开答案,再翻页 |
| ← | 上一步 |
| Esc | 总览所有页,点一页跳过去 |
| N | 打开 / 关闭讲解备注(给讲课的人看) |
| M | 打开 / 收起目录 |
| F | 全屏 |
标题后面有 卷子补充 的页,是原复习 PPT 没讲、但 2024 TT1 考到的内容。
List 和循环在附录仓库:List 与循环
PART 1 / 10
// ** %
// 整除:往下取整a // b = 不超过 a / b 的最大整数(floor)| 表达式 | a / b | 往下取整 | 结果 |
|---|---|---|---|
4 // 2 | 2.0 | 本来就是整数 | 2 |
3 // 2 | 1.5 | 1.5 → 1 | 1 |
2 // 3 | 0.666… | 0.666… → 0 | 0 |
7.0 // 2 | 3.5 | 3.5 → 3,有 float 所以是 3.0 | 3.0 |
-4 // 3 | -1.333… | -1.333… → -2 | -2 |
3 // 2 是 1,不是 2。-4 // 3 是 -2:从 -1.333… 往左找最近的整数。
int() 对比 卷子补充| 规则 | 7 / 2 = 3.5 | -4 / 3 = -1.33… | |
|---|---|---|---|
a // b | 往负无穷取整 | 3 | -2 |
int(a / b) | 砍掉小数,往 0 靠 | 3 | -1 |
卷子后面附的 API sheet 写着:int(x) 对 float 是 “truncated towards zero”。正数两者一样,负数不一样。
** 乘方a ** b 是 a 的 b 次方。Python 里 ^ 不是乘方。
| 表达式 | 结果 | 说明 |
|---|---|---|
2 ** 3 | 8 | |
2.5 ** 2 | 6.25 | 有 float,结果是 float |
2 ** -1 | 0.5 | 负指数得到 float |
(-1) ** 2 | 1 | 括号不能丢 |
2 ** 0 | 1 | 任何数的 0 次方是 1 |
% 取余数5 // 3 得到商 1,5 % 3 得到余数 2。
| 表达式 | 结果 | 怎么想 |
|---|---|---|
3 % 2 | 1 | 3 = 2 × 1 + 1 |
4 % 2 | 0 | 整除,余 0 |
2 % 4 | 2 | 不够除:商 0,余 2 |
-5 % 2 | 1 | 下一页用公式算 |
a % b 一定在 0 到 b - 1 之间。常见用法:n % 2 == 0 判断偶数,n % 10 取个位。// 和 %a % b = a - b * (a // b)
-5 % 2① 先算商:-5 / 2 = -2.5,往下取整 → -5 // 2 = -3
② 代入:-5 % 2 = -5 - 2 * (-3) = -5 + 6
③ 结果:1
验算:2 * (-3) + 1 = -5 ✓
% 不要凭感觉写 -1。先算 //,再代公式。(n // 这一位的位值) % 10。先用 // 去掉右边的位,再用 % 10 留下最后一位。| 要哪一位 | 写法 | n = 31487 |
|---|---|---|
| 个位 | n % 10 | 7 |
| 十位 | (n // 10) % 10 | 8 |
| 百位 | (n // 100) % 10 | 4 |
| 百位(另一种) | (n % 1000) // 100 | 4 |
2024 TT1 第 1 题就是这个:三位数取中间那一位。
| 优先级 | 运算符 |
|---|---|
| 最高 | () |
** | |
* / // % | |
+ - | |
< <= > >= == != in | |
not | |
and | |
| 最低 | or |
/ 永远得到 float:4 / 2 是 2.0。
看不清就自己加括号,考试也可以这样拆着算。
>>> -5 % 3>>> 5 / 2 ** 3 * 8 - 6
-5 // 3 = -2(-1.67 往下)
-5 - 3 * (-2) = -5 + 6 = 1
5 / (2 ** 3) * 8 - 6
= 5 / 8 * 8 - 6
= 5.0 - 6 = -1.0
PART 2 / 10
and 和 or混在一行里时,先看谁
| a | b | a and b | a or b |
|---|---|---|---|
| True | True | True | True |
| True | False | False | True |
| False | True | False | True |
| False | False | False | False |
and:全 True 才 True,有一个 False 就 False
or:有一个 True 就 True,全 False 才 False
not 先,and 其次,or 最后。and,先给它们打上括号。True or True and False
= True or (True and False)给 and 打括号
= True or False
= True
False and True or False and True
= (False and True) or (False and True)
= False or False
= False
and / or 返回的是操作数x and y:x 为假就返回 x,否则返回 yx or y:x 为真就返回 x,否则返回 y
>>> 0 and 1
>>> 1 and 2
>>> 0 or 5
>>> "" or "hi"0
2
5
'hi'0、""、[]、None 当条件用时算假,其余大多算真。
True or False and False or False and TrueTrue or False and True and True and False or True
① True or (False and False) or (False and True) → True or False or False → True
② True or (False and True and True and False) or True → True or False or True → True
小技巧:只要 or 连起来的某一段是 True,整个式子就是 True。
PART 3 / 10
if elif else
if / elif / elseif <condition>:
...
elif <condition>:
...
elif <condition>:
...
else:
...ifelif 可以有很多个else 最多一个,放最后,不写条件x = 75x = 75
if x >= 80:
print("A")
elif x >= 70:
print("B")
elif x >= 60:
print("C")
else:
print("F")75 >= 80?False,跳过
75 >= 70?True
打印 B
后面的 x >= 60 也是 True,但不会再检查
80+ A,70–79 B,60–69 C,50–59 D,不到 50 是 F。x 在 0 到 100。
if x >= 80:
print("A")
elif x >= 70:
print("B")
elif x >= 60:
print("C")
elif x >= 50:
print("D")
else:
print("F")if x < 50:
print("F")
elif x < 60:
print("D")
elif x < 70:
print("C")
elif x < 80:
print("B")
else:
print("A")为什么 B 不用写 x >= 70 and x < 80?
因为能走到这一行,就说明前面的 x >= 80 已经是 False,也就是 x < 80 已经确定了。所以这里只需要再判断 x >= 70。
x = 90
if x >= 50:
print("D")
elif x >= 80:
print("A") # 永远到不了Dx >= 50,就停在 D 了。如果 x 可能不在 0–100,就把区间写全,比如 elif 70 <= x < 80:。
if…elif 和两个独立的 if 不一样 卷子补充def f(x):
t = 0
if x > 10:
t = t + 10
elif x > 5:
t = t + 5
return tdef g(x):
t = 0
if x > 10:
t = t + 10
if x > 5:
t = t + 5
return t| x | f(x):只走一个分支 | g(x):两个 if 各自检查 |
|---|---|---|
| 12 | 10 | 15 |
| 8 | 5 | 5 |
| 3 | 0 | 0 |
2024 TT1 第 9 题的 func_b 就是两个独立的 if。
if age < 12:
price = 5
else:
if is_student:
price = 8
else:
price = 12if age < 12:
price = 5
elif is_student:
price = 8
else:
price = 12左右两段完全等价:else: 里只有一个 if 时,就等于 elif。
| age | is_student | price |
|---|---|---|
| 10 | True | 5(内层根本不看) |
| 20 | True | 8 |
| 20 | False | 12 |
2024 TT1 第 2 题:用表格反推嵌套 if 的两个空。
PART 4 / 10
函数里面的名字,和函数外面的名字
def triangle_area(base: float, height: float) -> float:
return base * height / 2
area = triangle_area(3, 4)| 部分 | 这里是 | 作用 |
|---|---|---|
| 函数名 | triangle_area | 调用时用的名字 |
| 参数 parameter | base, height | 函数里的 local 变量,调用时才有值 |
| 类型标注 | : float 和 -> float | 说明输入、输出应该是什么类型(type contract) |
return | base * height / 2 | 把结果交回去,并立刻结束函数 |
| 实参 argument | 3, 4 | 按位置交给参数:base = 3,height = 4 |
return 和 print 不是一回事 卷子补充def f(x):
print(x * 2)
def g(x):
return x * 2>>> a = f(3)
6
>>> b = g(3)
>>> print(a, b)
None 6print 只是把东西显示在屏幕上,函数的返回值还是 None。return 的函数,返回值就是 None。
return。题目问“返回什么”,看 return;问“打印什么”,看 print。>>> def f():
... x = 5
>>> f()
>>> xNameError: name 'x' is not defined调用 f() 时:
调用结束后,f 的这个框就没了:
>>> x = 4
>>> def f():
... x = 5
>>> f()
>>> x4两个 x 住在不同的框里。x = 5 是在 f 的框里新建一个 x,不是改外面那个。
global>>> x = 4
>>> def f():
... global x
... x = 5
>>> f()
>>> x5global x 写在函数里、用 x 之前。意思是:这个函数里的 x 就是外面那个 x。>>> x = 4
>>> def f():
... return x
>>> f()
>>> x4
4f 里没有给 x 赋值 → 去 global 找,读到 4
>>> x = 4
>>> def f():
... x = 5
... return x
>>> f()
>>> x5
4f 里给 x 赋过值 → 只用自己的 x
UnboundLocalError>>> y = 4
>>> def b():
... y += 2
... return y
>>> b()UnboundLocalError① y += 2 就是 y = y + 2,这是赋值
② 有赋值 → y 在 b 里是 local
③ 算右边 y + 2 时,local y 还没有值 → 报错
global y。或者别改 y,改成 return y + 2。x = 10
def add_one(x):
x = x + 1
return x
>>> add_one(3)
4
>>> x
10调用 add_one(3) 时,Python 先在新框里做一次 x = 3。
函数里怎么改参数,外面的 x 都还是 10。
def f(y, x):
return y - x
>>> x = 1
>>> y = 5
>>> f(x, y)调用 f(x, y) 就是 f(1, 5)
第一个位置给 y:y = 1
第二个位置给 x:x = 5
返回 1 - 5 = -4
2024 TT1 第 8 题 well(y, x)、hello(z, x) 就是专门考这个。
a() 返回什么?def a():
y = 3 * x * z
return y * b()
def b():
z = 5
return 4 * x * z
x = 3
z = 4
a()global:x = 3,z = 4
a 里没给 x、z 赋值 → 用 global:y = 3 * 3 * 4 = 36
b 里 z 是 local 5,x 还是 global 3:4 * 3 * 5 = 60
a() 返回 36 * 60 = 2160
PART 5 / 10
下标 · slicing · 拼接 · 比较 · 方法
print 的输出输入两种写法,字符串的内容相同
>>> 'cat'
>>> "cat"'cat'
'cat'print 只把内容印出来
>>> print('cat')
>>> print("cat")cat
catrepr(表示形式);外层引号提示“这是字符串”,不是字符串内容。print 显示内容。>>> "It's OK"
>>> 'It\'s OK'"It's OK"
"It's OK">>> print("It's OK")
>>> print('It\'s OK')
>>> print('"Hi"')It's OK
It's OK
"Hi"\' 转义,或改用双引号包住。repr 会选合适的外层引号:"It's OK" 在交互终端显示双引号。所以“终端永远显示单引号”不成立。蓝色是从左数(从 0 开始),橙色是从右数(从 -1 开始)。
0 … n-1,负下标 -1 … -n。s[0] 是第一个,s[-1] 是最后一个,s[n-1] 也是最后一个。
IndexError:"abc"[3]。slicing 越界不会报错。"Minecraft" 里的 'a''a'? a. 6 b. 7 c. -3 d. -2s[6] 和 s[-3] 是同一个格子。7 和 -2 都是 'f'。s = 'ABCDE':蓝色数字是字符下标;下方 0…5 是字符之间的切割位置。
① s[2:4] 从位置 2 开始,也就是 C 前面。
② 到位置 4 停,在 E 前面切开。
③ 先取下标 2 的 C。
④ 再取下标 3 的 D;下标 4 的 E 不取。结果 'CD'。
s = 'ABCDE',len(s) = 5;合法字符下标只有 0…4。
s[2:10] → 'CDE'。10 是终点上限,超出长度也不会报错;切片不会生成下标 5…9 的字符。s[10] 会报 IndexError。>>> x = "University of Toronto"
>>> x[14:20]
>>> x[14:21]
>>> x[14:]
'Toront'
'Toronto'
'Toronto's[start:stop] 从 start 开始,到 stop 前一个为止。黄色就是 x[14:20],20 号的 'o' 不算。结果是一个新字符串,原来的 x 不变。
| 写法 | 结果 | 说明 |
|---|---|---|
s[:3] | 'Tor' | 省略 start:从头开始 |
s[3:] | 'onto' | 省略 stop:一直到最后,包括最后一个 |
s[-4:] | 'onto' | -4 就是 3 号格 |
s[:] | 'Toronto' | 整串复制一份 |
s[3:100] | 'onto' | 越界不报错,切到末尾为止 |
s[5:2] | '' | 起点在终点右边 → 空字符串 |
Computer 和 Sciencez = "Computer Science",写出几种能得到 'Computer' 或 'Science' 的切法。Computer:z[:8] z[0:8] z[:-8] z[0:-8] z[-16:-8] z[-16:8]
Science:z[9:] z[9:16] z[-7:] z[-7:16]
起点终点可以一正一负。先把负数换成格子位置(-8 就是 8 号格的空格),再看范围。
x = "0123456789"
x[::2] → '02468':从 0 开始,每次 +2
x[1::2] → '13579':从 1 开始,每次 +2
s[start:stop:step]:先确定范围和方向;从 start 开始,每次加 step,到达或越过 stop 时停止。stop 不取。s = 'ABCDEFGHIJK',计算 s[3:10:3]
s[3:10]:DEFGHIJ(K 在下标 10,不包含)x = "0123456789"
x[::-2] → '97531':省略 start 时从最后一个开始,每次 -2
x[-2::-2] → '86420':从 -2(字符 8)开始往左
s = 'ABCDE',计算 s[4:0:-1]。负步长时,stop=0 仍然不包含。
s[4:0:-1] → 'EDCB'。反向的规则也是“取 start,不取 stop”。s[::-1]:省略 start,从最后一个 E 出发。
接着取 D。
接着取 C。
接着取 B。
最后取 A → 'EDCBA'。
s[4:-1:-1] 却是 '':显式 -1 指向最后一个字符 E,它是不包含的终点。省略 stop 才会一直走过 A。''>>> s = "Mississauga"
>>> s[0:11:-1]
>>> s[::-1]
>>> s[8:2]
''
'aguassissiM'
''s[0:11:-1]:起点 0 不在向左切片的有效范围内 → '',连第一个字符也不取。
s[::-1]。step 不能为 0:s[::0] 会报 ValueError。+ 拼接,* 重复 卷子补充>>> "We're" + "Here"
>>> 'abc' * 2
>>> 'ab' * 0
>>> "Total: " + str(10)
>>> "Total: " + 10"We'reHere"
'abcabc'
''
'Total: 10'
TypeErrorstr + int 会 TypeError。要先 str(10) 把数字变成字符串。'abc' * 2 是整串重复 'abcabc',不是每个字母重复 'aabbcc'。2024 TT1 第 7 题用到。
in:有没有这个子串 卷子补充>>> 'cat' in 'concatenate'
>>> 'o' in 'Welcome'
>>> 'CS' in 'csc108'
>>> '' in 'abc'True
True
False
Truex in s 问的是:x 是不是 s 里连续的一段。大小写要一致。| 字符 | 编码(ord) |
|---|---|
'0' – '9' | 48 – 57 |
'A' – 'Z' | 65 – 90 |
'a' – 'z' | 97 – 122 |
'9' < 'A' < 'Z' < 'a' < 'z'ord('a') 是 97,chr(66) 是 'B'。API sheet 上有这两个函数。
像查字典:字母一样就看下一个,第一个不一样的字母决定谁更小。
'car' 和 'cat'
c 一样,a 一样。
第三个 r 比 t 靠前,所以 'car' < 'cat'。
'app' 和 'apple'
前面 app 都一样。
'app' 先结束,短的更小,所以 'app' < 'apple'。
| 表达式 | 第一个不同的地方 | 结果 |
|---|---|---|
'tmu' < 'utsg' | 't' vs 'u' | True |
'utsg' > 'utsc' | 'g' vs 'c' | True |
'utm' > 'utmsu' | 'utm' 先比完,短的更小 | False |
'Zoo' < 'apple' | 'Z'(90) vs 'a'(97) | True |
连着写 'a' < 'b' < 'c' 时,Python 会拆成两小段,两段都要成立:'a' < 'b' 是 True(a 在 b 前面),'b' < 'c' 也是 True(b 在 c 前面),所以整个结果是 True。
不是先算出 True,再拿这个 True 去和 'c' 比。
| 方法 | 例子 | 结果 |
|---|---|---|
s.count(sub) | 'banana'.count('a') | 3 |
s.find(sub) | 'banana'.find('an') | 1(最左边的起点) |
s.find(sub, i) | 'banana'.find('a', 2) | 3(从下标 2 开始找) |
s.rfind(sub) | 'banana'.rfind('a') | 5(最右边的起点) |
s.find(sub) 找不到 | 'banana'.find('z') | -1 |
s.index(sub) 找不到 | 'banana'.index('z') | ValueError |
find 找不到返回 -1,index 找不到报错。s.lower() 返回一个新的,要留下就写 s = s.lower()。| 方法 | 按 → 看它做什么 |
|---|---|
lower()'CsC108'.lower() |
每个字母变小写,数字不动 → 'csc108' |
upper()'CsC108'.upper() |
每个字母变大写,数字不动 → 'CSC108' |
capitalize()'hELLO'.capitalize() |
只把第一个字符变大写,后面全部变小写 → 'Hello' |
名字要写对:没有 lowercase(),只有 lower()。写错是 AttributeError。
灰色块是空格。这些方法同样不改原来的字符串。
| 方法 | 按 → 看它做什么 |
|---|---|
strip()' hi '.strip() |
去掉两边的空格,中间的字留下 → 'hi' |
lstrip()' hi '.lstrip() |
只去掉左边,右边的空格还在 → 'hi ' |
rstrip()' hi '.rstrip() |
只去掉右边,左边的空格还在 → ' hi' |
replace(old, new)'a-b-c'.replace('-', '+') |
每一处 '-' 都换成 '+',不是只换第一次 → 'a+b+c'。new 写成 '' 就是把它们删掉。 |
空字符串 '' 用这些方法,结果都是 False。也是返回 True / False,不改原来的字符串。
| 方法 | 按 → 看它做什么 |
|---|---|
isdigit()'108'.isdigit() |
每个字符都是数字才是 True → True。'10a' 是 False |
isalpha()'csc'.isalpha() |
每个字符都是字母才是 True → True。'csc108' 是 False |
isalnum()'csc108'.isalnum() |
每个字符是字母或数字才是 True → True。'c-s' 是 False |
islower()'csc108'.islower() |
字母都是小写,而且至少有一个字母 → True。数字不管。'CsC' 和 '108' 都是 False |
isupper()'CSC108'.isupper() |
字母都是大写,而且至少有一个字母 → True。'Csc' 是 False |
PART 6 / 10
Function Design Recipe · test cases · refactoring
def is_even(n: int) -> bool:
"""Return True iff n is even.
>>> is_even(4)
True
>>> is_even(3)
False
"""
return n % 2 == 0名字:is_even。一看就知道是在判断偶数。
type contract:参数 n: int,返回 bool。
docstring:""" 里的一句话,说它做什么。
doctest:>>> 后面是调用,下一行是期望结果。
函数体:照着上面那句话写出来的代码。
测试:跑这些例子。4 应该得到 True,3 应该得到 False。
>>> 和后面的文字之间要有一个空格。>>>is_even(4) 不会被当成测试;要写成 >>> is_even(4)。def triangle_area(base: float, height: float) -> float:
"""Return the area of a triangle with base and height.
>>> triangle_area(2, 3)
3.0
>>> triangle_area(4, 5)
10.0
"""
return base * height / 2""" 包起来>>> 后面写调用,下一行写期望结果def has_digit(s: str) -> bool:
"""Return True iff s contains
at least one digit."""
for ch in s:
if ch.isdigit():
return True
return False用参数名。 函数头里叫 s,答案里就写 s。循环里的 ch 不要写进去。
开头写 Return。 只说交出去什么,不要把代码逐行翻译一遍。
交出去的是 True 或 False,所以写 True。iff 是 if and only if,就是“当且仅当”:后面那句话成立 → True,不成立 → False。
返回类型看 return 后面那个值,不是前面数过的变量。
| return 后面 | 按 → 看交出去什么 | 类型 |
|---|---|---|
return True |
后面就是 True → | bool |
return c == n |
== 只问相不相等。2 == 2 → True,2 == 3 → False。不是把数字 c 交出去 → |
bool |
例子:letter(x),0 ≤ x ≤ 100,80 分以上 A,70–79 B …… 50 以下 F
| 测什么 | x | 期望 |
|---|---|---|
| 一般情况(每个分支至少一个) | 90 | 'A' |
| 边界:刚好等于分界值 | 80 | 'A' |
| 边界:分界值下面一点 | 79 | 'B' |
| 范围最小值 | 0 | 'F' |
| 范围最大值 | 100 | 'A' |
题目说了范围(如 0.0 ≤ score ≤ 4.0),测试值就不能超出范围。2024 TT1 第 12 题。
if n % 2 == 0:
return True
else:
return Falsereturn n % 2 == 0if flag == True:
...if flag:
...if a > 5:
return True
if b > 5:
return True
if a > 5:
return False
return False两个分支都返回 True → 用 or 合并
走到第 5 行时 a > 5 一定已经是 False,这个 if 永远不会成立,删掉
return a > 5 or b > 52024 TT1 第 13 题就是这类。
PART 7 / 10
看最后一行:错误类型 + 原因
| Error | 例子 | 原因 |
|---|---|---|
| NameError | y(从没赋值) | 这个名字不存在 |
| TypeError | "Total: " + 10 | str 不能和 int 相加 |
| TypeError | 'a' - 'a' | 字符串不能相减 |
| IndexError | 'abc'[3] | 下标越界 |
'a' < 'b'
'a' - 'a'
ord('a') - ord('a')只有比较才不用 ord。'a' < 'b' 直接比谁靠前。
相减不是比较。减号不会自动查编码 → TypeError。
要减编码得自己写 ord:97 − 97 → 0。
a = print(1)
a[0]None 表示“没有东西”。不是 0,也不是 ""。
屏幕写出 1,交回来的是 None,所以 a 是 None。
None 没有格子。a[0] 就是 None[0] → TypeError。
int(2.0)
int('2.0')
int(float('2.0'))2.0 已经是数字。int 往 0 砍 → 2。
'2.0' 是文字。int 读文字时不认小数点 → ValueError。
先 float('2.0') 变成 2.0,再砍 → 2。
'abc'.find('z')
'abc'.index('z')'abc' 里没有 z。find 找不到就返回 -1。
同样找不到,index 不返回 -1,直接 ValueError。
3 / 0
3 % 0除数是 0。/、%、// 都算不了 → ZeroDivisionError。
'June'.lowercase()
'June'.lower()str 没有 lowercase 这个方法 → AttributeError。
要写 lower() → 'june'。
y = 4
def b():
y += 2y += 2 就是 y = y + 2,这是赋值。
函数里赋值过,y 全程是 local。算右边时还没值 → UnboundLocalError。
外面的 y = 4 用不上。要改它,函数第一行写 global y。
if x > 0:
print(x)if 下面必须缩进。print 和 if 对齐,Python 看不到 if 的身体 → IndentationError。
PART 8 / 10
按课件里的英文定义记
| 词 | 定义 |
|---|---|
| Floating point浮点数 | A decimal or fractional number.小数,或带分数部分的数。 |
| Floating-point error浮点误差 | Repeated decimals are stored as approximations.循环小数存下来的是近似值。 |
| Variable变量 | A name given to a value.给一个值起的名字。 |
| Assignment赋值 | = binds a name to a value. It is not mathematical equality.= 把名字绑到一个值上。它不是数学里的等于。 |
| Function函数 | Code that can be called by name.一段可以用名字调用的代码。 |
| return返回 | A reserved word. It sends a value back to the caller and exits the function.保留字。把值交回调用的人,并且结束这个函数。 |
| 词 | 定义 |
|---|---|
| Docstring文档字符串 | A short description of a function. Be concise and precise.对函数的简短说明。要短,也要准确。 |
| Scope作用域 | The places where a variable’s name is valid.一个变量名在哪些地方有效。 |
| Global variable全局变量 | A variable that can be accessed by all functions (unless a local name hides it).所有函数都能用的变量,除非里面有同名的 local 把它挡住。 |
| String字符串 | Text inside quotes; an ordered collection of characters.引号里的文字;按顺序排好的一串字符。 |
| Newline / tab换行 / 制表符 | \n starts a new line; \t is a tab.\n 另起一行;\t 是制表符。 |
| Method方法 | A function designed for one type, called as value.method(...).给某一种类型用的函数,调用时写成 value.method(...)。 |
| 词 | 定义 |
|---|---|
| if statementif 语句 | A control structure that runs a block when its condition is True.一种控制结构:条件是 True 时,才运行下面那一块。 |
| Factoring分解问题 | Breaking a complex problem into parts that are easier to understand, program, and maintain.把复杂问题拆成几块,让它更好懂、好写、也好维护。 |
| Refactoring重构 | Restructuring existing code without changing its external behaviour.调整已有代码的结构,但外面的行为不变。 |
| 调用 | 按 → 看它做什么 |
|---|---|
print(1) |
屏幕写出 1,交回来的是 None。要留下结果,用 return。 |
len('hi')len([1, 2, 3]) |
问有几个 → 2,和 3。字符串数字符,list 数元素。 |
str(10) |
变成文字 → '10'。和字符串相加之前要先变,否则 TypeError。 |
float('2.5')float(2) |
变成小数 → 2.5,和 2.0。 |
bool(0)bool('hi') |
0、""、[]、None 是 False。别的大多是 True,所以 'hi' → True。 |
int('12')int('2.0')int(-2.7) |
'12' → 12。'2.0' 是文字,不认小数点 → ValueError。-2.7 往 0 砍 → -2,不是 -3。 |
| 调用 | 按 → 看它做什么 |
|---|---|
type(3)type(None) |
问类型 → <class 'int'>,<class 'NoneType'>。 |
max(3, 1, 4)min('cat', 'car') |
最大的 → 4。字符串按字典序,'car' 更小 → 'car'。 |
ord('a')chr(97) |
字符 → 编码 97。编码 → 字符 'a'。比较不用 ord,相减才要。 |
input() |
读用户打的一行,结果永远是 str。打 12 得到 '12',要数字再套 int。 |
None(改原来的东西)print
lower、upper、capitalize、strip、lstrip、rstrip、replace
x in s、isalpha、isdigit、islower、isupper
len、count、find(找不到 -1)、index(找不到报错)、ord
-> 后面写的就是返回类型。看到 -> None,就别把结果赋值给变量。PART 9 / 10
先做,再按 →
print(int("1"))
print(float("-.8"))
print(float("2"))
print(int("2.0"))前三行分别打印 1、-0.8、2.0
答案 c。int("2.0") 是 ValueError:int 读字符串时不认小数点。要写 int(float("2.0"))。
"Mississauga" 切片>>> a = "Mississauga"
>>> a[::3]
>>> a[0:11:-1]"Mssg", """ssu", """Mssg", "aguassissiM""ssu", "aguassissiM"答案 A。下标 0、3、6、9 是 M、s、s、g。a[0:11:-1] 从 0 往左走,到不了 11 → ''。
x = 3
y = 4
def a():
global x
x += 2
return x
def b():
y += 2
return y
a()
b()为什么 x 变成 5? global x 就是“用外面那个 x”。x += 2 等于 x = 3 + 2,5 写回外面。
为什么 y 还是 4,还报错? b 没写 global y。y += 2 是赋值,这个 y 全程是自己的。算 y + 2 时自己还没值,不会去读外面的 4 → UnboundLocalError。
报错发生在改 y 之前,外面的 4 还在。a() 已经把 x 改完。最后 x = 5,y = 4。
控制结构只管两件事:哪些代码要跑,以及要跑几次。if 看条件,决定跑不跑这块;loop 决定这块重复几次。所以只有这两项。
为什么赋值不是? x = 3 只是把值存下来。这一行写了就会执行,不会跳过,也不会重复。
为什么函数、方法不是? f()、s.lower() 是去调用一段写好的代码。调用本身不负责挑路。
为什么表达式、运算不是? 1 + 2 是在算出一个结果。算完就结束,不管别的代码跑不跑。
| 代码 | Error |
|---|---|
'a' - 'a' | TypeError |
'abc'[3] | IndexError |
3 / 0 | ZeroDivisionError |
x = 3 然后 y | NameError |
| 题目 | 答案 | 过程 |
|---|---|---|
-200 % 17 | 4 | -200 // 17 = -12,-200 - 17 * (-12) = 4 |
True and False or False and False or True or False and True | True | and 先算:False or False or True or False |
5 / 8 * 2 ** 3 + 4 | 9.0 | 5 / 8 * 8 + 4 = 5.0 + 4 |
用 a、b 填 a = _ % _ + _ // _ * _ | a = a % b + a // b * b | |
replace 换掉全部>>> "abs sabs eeabs".replace("abs", "s")'s ss ees'三处 abs 都换成 s:abs → s,sabs → ss,eeabs → ees。空格保留。
def index_of_the_second_sub(s: str, sub: str) -> int:
"""Return the index of the second sub in s.
If s contains fewer than 2 subs, return -1.
>>> index_of_the_second_sub("abcabc", "abc")
3
>>> index_of_the_second_sub("", "a")
-1
"""
return s.find(sub, s.find(sub) + len(sub))内层 s.find(sub):第一次出现的起点,"abcabc" 里是 0
+ len(sub):跳过第一次,从 3 开始找
外层 find 从 3 找到 3;找不到就是 -1
PART 10 / 10
8 题 · 选择题注意 “Circle ALL” 是多选
a 是一个正的三位数。哪个表达式得到 a 的中间一位?(a = 456 时要得到 5)
(a // 10) % 10(a % 100) // 10(a % 10) // 10| a = 456 | |
|---|---|
| A | 45 % 10 = 5 ✓ |
| B | 56 // 10 = 5 ✓ |
| C | 6 // 10 = 0 ✗ |
A 和 B 都对,所以答案是 D。
| plan \ months | 1 | 2–6 | 7+ |
|---|---|---|---|
| silver | $90 | $60 | $60 |
| gold | $90 | $70 | $35 |
if months == 1:
cost = 90
elif ____(1)____:
cost = 60
else:
if ____(2)____:
cost = 70
else:
cost = 35plan == 'silver'months >= 2 and months <= 6plan == 'silver'months >= 6months >= 2 and months <= 6plan == 'gold'(1) 要覆盖 silver 至少 2 个月的 60 元:填 plan == 'silver'。
进入 else 已排除第 1 个月和 silver;gold 的 2–6 个月收 70 元,所以 (2) 要检查月份在 2 到 6 之间。
B 会把 gold 3 个月算成 35 元、7 个月算成 70 元,都不对。答案 A。
s = "We're" + "Here"
print(s[4::2])s = "We'reHere",共 9 个字符:
eHereeeerHr'eee从下标 4 开始每次 +2:4、6、8 → e、e、e。答案 B。撇号在下标 2,取不到。
x = 5
y = 2
z = True
def well(y, x):
z = 3
x = y
y = x
return x * y * z
def hello(z, x):
x = z + x
z = y + x
return well(x, z)调用 hello(0, 1) 之后,global 的 x、y、z 是多少?
hello(0, 1):按位置 z = 0,x = 1(都是 local)
x = 0 + 1 = 1
hello 里没有 y → 读 global 的 2:z = 2 + 1 = 3
well(1, 3):按位置 y = 1,x = 3
z = 3,x = 1,y = 1,返回 1 * 1 * 3 = 3
没有 global,所有赋值都在各自的框里 → A。不会报错,因为 hello 只是读 y。
def func_a(value):
total = 0
if value >= 15:
total = total + 20
elif value >= 10:
total = total + 10
else:
total = total + 1
return totaldef func_b(value):
total = 0
if value > 10:
total = total + 10
if value <= 5:
total = total + 5
else:
total = total + 2
return total| 代码 | 输出 | 走了哪些行 |
|---|---|---|
print(func_a(5)) | 1 | 两个条件都不满足 → else |
print(func_b(8)) | 2 | 8 > 10 否;8 <= 5 否 → else +2 |
print(func_a(15)) | 20 | 第一个条件就成立,后面不看 |
print(func_b(12)) | 12 | 两个独立的 if:先 +10,再走 else +2 |
前往模拟网站(大家可以收藏) https://pythontutor.com/cp/csc108h.html#mode=edit
def performance_eval(score: float) -> str:
"""0.0 <= score <= 4.0
Return 'outstanding' if score is at least 3.5, 'exceeds expectations'
if score is at least 3.2 and less than 3.5, and 'needs improvement' otherwise.
"""| Test Case Description | score | Return Value |
|---|---|---|
| Score below 3.2(题目给的) | 2.5 | 'needs improvement' |
| Boundary: exactly 3.2 | 3.2 | 'exceeds expectations' |
| Between 3.2 and 3.5 | 3.4 | 'exceeds expectations' |
| Boundary: exactly 3.5 | 3.5 | 'outstanding' |
| Maximum score | 4.0 | 'outstanding' |
也可以换成 0.0(最小值)或 3.19(刚好低于 3.2)。不能用 4.5、-1 这种超出范围的值。
def func(x, y):
if x > 100 and y == 0:
return True
if x > 100 and y != 0:
return True
if x > 100:
return False
elif x < 0 and y == 10:
return True
return False① y 要么 == 0 要么 != 0 → 两个 if 合起来就是 “x > 100 就 True”
② 能走到第 6 行,x > 100 一定是 False,这个分支永远到不了,删掉
③ 剩下:
x < 0 and y == 10 时 True
def func(x, y):
return x > 100 or (x < 0 and y == 10)④ 其余都是 False
括号可以不写(and 本来就先算),写上更清楚。我用 x ∈ [-50, 200)、y ∈ [-5, 20) 全部代进去比过,结果和原函数完全一样。
CURRENT_YEAR = 2023
def calculate_age(birth_date: str) -> int:
"""birth_date 的格式是 YYYY-MM-DD,不晚于 CURRENT_YEAR 年底。
返回这个人在 CURRENT_YEAR 年底的年龄。
>>> calculate_age('2010-05-15')
13
>>> calculate_age('1995-10-20')
28
>>> calculate_age('2023-01-01')
0
"""return CURRENT_YEAR - int(birth_date[:4])birth_date[:4] → '2010',int(...) → 2010
问的是“年底”的年龄,月和日不影响:2023 - 2010 = 13
要用常量 CURRENT_YEAR,不要写死 2023
// 往负无穷取整,int() 往 0 砍;% 用 a = b * (a // b) + a % b 验算(n // 位值) % 10and 先于 orif/elif 只走一个分支;两个独立 if 各自检查return 就返回 None'abc' * 2 是 'abcabc';str + int 报错卡住时点目录跳回对应的那一章,用例子再算一遍。