程序改错题解析
第1题:温度转换
题目: 将输入的摄氏温度转换为华氏温度并输出。转换公式:F = C * 9 / 5 + 32。
| Python |
|---|
| #**********begin1**********
c = input("请输入摄氏温度:") # ❌ 错误1
#**********end1**********
#**********begin2**********
f = c * 9 // 5 + 32 # ❌ 错误2
#**********end2**********
#**********begin3**********
print("华氏温度为:" + f) # ❌ 错误3
#**********end3**********
|
✅ 错误修正
| 错误位置 |
原代码 |
修正后 |
错误原因 |
| begin1 |
c = input("请输入摄氏温度:") |
c = int(input("请输入摄氏温度:")) |
input() 返回字符串,需要转为整数 |
| begin2 |
f = c * 9 // 5 + 32 |
f = c * 9 / 5 + 32 |
// 是整除,会丢失小数部分,应用 / 精确除法 |
| begin3 |
print("华氏温度为:" + f) |
print(f"华氏温度为:{f}") 或 print("华氏温度为:" + str(f)) |
f 是浮点数,不能与字符串直接拼接 |
完整正确代码
| Python |
|---|
| c = int(input("请输入摄氏温度:")) # ✅ 修正1:int() 转为整数
f = c * 9 / 5 + 32 # ✅ 修正2:/ 精确除法
print(f"华氏温度为:{f}") # ✅ 修正3:f-string 格式化输出
# 输入 25 时,输出: 华氏温度为:77.0
# 输入 37 时,输出: 华氏温度为:98.6
|
解析:
-
错误1:input() 函数返回的是字符串类型。如果输入 25,c 的值是 "25"(字符串),不是 25(整数)。需要用 int() 将字符串转为整数,否则后续运算会出错(字符串乘整数是重复操作)
| Python |
|---|
| c = input("请输入:") # 输入 25 → c = "25"(字符串)
c * 9 # "25" * 9 = "25252525252525252525"(字符串重复!)
int(c) * 9 # 25 * 9 = 225(数值运算 ✅)
|
-
错误2:// 是整除运算符,只保留整数部分。例如 225 // 5 = 45,而 225 / 5 = 45.0。当结果不能整除时会丢失精度,如 37 * 9 // 5 = 66(实际应为 66.6)。温度转换应使用 / 保证精度
-
错误3:f 是浮点数(float),Python 不允许字符串与浮点数直接用 + 拼接,会报 TypeError。解决方案:
- f-string:
f"华氏温度为:{f}"(推荐)
str() 转换:"华氏温度为:" + str(f)
🔑 知识点:输入输出与类型转换
| 转换函数 |
用途 |
示例 |
int() |
转整数 |
int("25") → 25 |
float() |
转浮点数 |
float("3.14") → 3.14 |
str() |
转字符串 |
str(25) → "25" |
| 运算符 |
含义 |
示例 |
/ |
精确除法 |
7 / 2 → 3.5 |
// |
整除(向下取整) |
7 // 2 → 3 |
% |
取余 |
7 % 2 → 1 |
- 字符串与数值拼接方式:
- f-string:
f"值:{x}"(推荐)
str() 转换:"值:" + str(x)
print 多参数:print("值:", x)
📖 拓展
| Python |
|---|
| # 更完善的温度转换程序
c = float(input("请输入摄氏温度:")) # float 支持小数输入
f = c * 9 / 5 + 32
print(f"摄氏 {c}°C = 华氏 {f:.1f}°F") # .1f 保留1位小数
# 反向转换:华氏转摄氏
f = float(input("请输入华氏温度:"))
c = (f - 32) * 5 / 9
print(f"华氏 {f}°F = 摄氏 {c:.1f}°C")
# 常见温度对照
# 0°C = 32°F (冰点)
# 100°C = 212°F (沸点)
# 37°C = 98.6°F(体温)
|
第2题:列表最大值
题目: 遍历列表,找出并输出其中的最大值。
| Python |
|---|
| nums = [23, 45, 12, 67, 34]
max_num = nums[0]
for num in nums:
#**********begin1**********
if num < max_num # ❌ 错误1
#**********end1**********
#**********begin2**********
max_num == num # ❌ 错误2
#**********end2**********
print(f"最大值:{max_num}")
|
✅ 错误修正
| 错误位置 |
原代码 |
修正后 |
错误原因 |
| begin1 |
if num < max_num |
if num > max_num |
求最大值应在当前元素更大时更新,比较方向反了 |
| begin2 |
max_num == num |
max_num = num |
== 是比较运算符,= 才是赋值运算符 |
完整正确代码
| Python |
|---|
| nums = [23, 45, 12, 67, 34]
max_num = nums[0]
for num in nums:
if num > max_num: # ✅ 修正1:大于才更新
max_num = num # ✅ 修正2:赋值用 = 不是 ==
print(f"最大值:{max_num}")
# 输出: 最大值:67
|
解析:
-
错误1:num < max_num 表示"当前元素比最大值小",此时更新最大值毫无意义——应该更新的是当遇到更大的元素时。求最大值的逻辑是:当 num > max_num(当前元素更大)时,才更新 max_num
| Python |
|---|
| # 错误逻辑:遇到比最大值还小的才更新
# 结果:max_num 永远不会变大(初始值就是第一个元素)
# 实际效果:max_num 始终为 nums[0] = 23
# 正确逻辑:遇到比最大值更大的才更新
if num > max_num:
max_num = num
|
-
错误2:== 是比较运算符,返回 True 或 False,不会修改变量的值。max_num == num 只是比较两者是否相等,结果被丢弃。正确写法是 max_num = num,用 = 赋值
| Python |
|---|
| max_num == num # 比较:返回 True/False,max_num 不变
max_num = num # 赋值:将 num 的值存入 max_num ✅
|
🔑 知识点:赋值与比较
| 运算符 |
含义 |
用途 |
示例 |
= |
赋值 |
将右边的值存入左边的变量 |
x = 5(x 变为 5) |
== |
比较 |
判断两边的值是否相等 |
x == 5(返回 True/False) |
| Python |
|---|
| # 求最大值
max_val = lst[0]
for item in lst:
if item > max_val: # 遇到更大的
max_val = item # 更新最大值
# 求最小值
min_val = lst[0]
for item in lst:
if item < min_val: # 遇到更小的
min_val = item # 更新最小值
|
📖 拓展
| Python |
|---|
| # 方法2:使用内置函数
nums = [23, 45, 12, 67, 34]
print(max(nums)) # 67
print(min(nums)) # 12
# 方法3:使用排序
nums_sorted = sorted(nums)
print(nums_sorted[-1]) # 最大值:67
print(nums_sorted[0]) # 最小值:12
# 方法4:同时求最大值和最小值
def find_max_min(lst):
max_val = min_val = lst[0]
for item in lst:
if item > max_val:
max_val = item
if item < min_val:
min_val = item
return max_val, min_val
maximum, minimum = find_max_min([23, 45, 12, 67, 34])
print(f"最大值:{maximum},最小值:{minimum}")
|
第3题:文件写入
题目: 将文本内容写入文件 output.txt。
| Python |
|---|
| #**********begin1**********
f = open("output.txt", "r") # ❌ 错误1
#**********end1**********
#**********begin2**********
f.writeline("Hello, World!\n") # ❌ 错误2
#**********end2**********
f.writelines(["Line 1\n", "Line 2\n"])
#**********begin3**********
f.close # ❌ 错误3
#**********end3**********
|
✅ 错误修正
| 错误位置 |
原代码 |
修正后 |
错误原因 |
| begin1 |
open("output.txt", "r") |
open("output.txt", "w") |
"r" 是只读模式,无法写入;写入文件应使用 "w" 模式 |
| begin2 |
f.writeline(...) |
f.write(...) |
文件对象没有 writeline 方法,正确的方法是 write |
| begin3 |
f.close |
f.close() |
close 是方法,必须加括号 () 才能调用 |
完整正确代码
| Python |
|---|
| f = open("output.txt", "w") # ✅ 修正1:写入模式 "w"
f.write("Hello, World!\n") # ✅ 修正2:write 方法
f.writelines(["Line 1\n", "Line 2\n"])
f.close() # ✅ 修正3:调用 close() 方法
# output.txt 内容:
# Hello, World!
# Line 1
# Line 2
|
解析:
-
错误1:"r" 是只读模式(read),尝试写入会报 UnsupportedOperation 错误。写入文件应使用 "w" 模式(write)。如果文件不存在,"w" 模式会自动创建;如果文件已存在,"w" 模式会覆盖原内容
| Python |
|---|
| open("file.txt", "r") # 只读,不可写入
open("file.txt", "w") # 只写,覆盖已有内容
open("file.txt", "a") # 追加,在文件末尾添加
open("file.txt", "r+") # 读写
|
-
错误2:文件对象没有 writeline 方法。正确的方法是 write(),用于写入单个字符串。注意 writelines() 是另一个方法,用于写入字符串列表,但它不会自动添加换行符
| Python |
|---|
| f.write("Hello\n") # 写入单个字符串 ✅
f.writelines(["A\n", "B\n"]) # 写入字符串列表 ✅
f.writeline("Hello\n") # ❌ 不存在此方法!
|
-
错误3:f.close 只是引用了 close 方法对象,并没有调用它。必须加 () 才能执行关闭操作:f.close()。不加括号的话文件不会被关闭,可能导致数据丢失
| Python |
|---|
| f.close # 只是一个方法对象的引用,不会关闭文件
f.close() # 调用方法,关闭文件 ✅
|
🔑 知识点:文件操作
| 模式 |
含义 |
文件存在时 |
文件不存在时 |
"r" |
只读 |
读取内容 |
报错 FileNotFoundError |
"w" |
只写 |
覆盖内容 |
创建新文件 |
"a" |
追加 |
末尾添加 |
创建新文件 |
"r+" |
读写 |
读取+写入 |
报错 |
| 方法 |
参数 |
说明 |
write(s) |
字符串 |
写入单个字符串 |
writelines(lst) |
字符串列表 |
写入多个字符串,不自动换行 |
| Python |
|---|
| with open("output.txt", "w") as f:
f.write("Hello, World!\n")
f.writelines(["Line 1\n", "Line 2\n"])
# 离开 with 块后文件自动关闭,无需手动调用 close()
|
📖 拓展
| Python |
|---|
| # 方法1:手动打开和关闭
f = open("output.txt", "w")
f.write("Hello, World!\n")
f.close()
# 方法2:with 语句(推荐,自动关闭)
with open("output.txt", "w") as f:
f.write("Hello, World!\n")
f.writelines(["Line 1\n", "Line 2\n"])
# 方法3:追加模式
with open("output.txt", "a") as f:
f.write("Line 3\n") # 在文件末尾追加
# 方法4:读取文件内容
with open("output.txt", "r") as f:
content = f.read() # 读取全部内容
# lines = f.readlines() # 按行读取为列表
print(content)
|
📌 记忆要点
-
写文件用 "w" 模式,读文件用 "r" 模式,追加用 "a" 模式
-
写入方法:write() 写单个字符串,writelines() 写字符串列表
-
方法调用必须加括号:f.close() 不是 f.close
-
推荐使用 with open(...) as f: 自动管理文件
第4题:素数判断
题目: 判断输入的正整数是否为素数,并输出结果。
| Python |
|---|
| def is_prime(n):
if n < 2:
return False
#**********begin1**********
for i in range(1, n): # ❌ 错误1
#**********end1**********
#**********begin2**********
if n / i == 0: # ❌ 错误2
#**********end2**********
return False
return True
num = int(input("请输入一个正整数:"))
#**********begin3**********
if is_prime num: # ❌ 错误3
#**********end3**********
print(f"{num}是素数")
else:
print(f"{num}不是素数")
|
✅ 错误修正
| 错误位置 |
原代码 |
修正后 |
错误原因 |
| begin1 |
range(1, n) |
range(2, n) |
从1开始会使 n%1==0 恒成立,所有数都被判为非素数 |
| begin2 |
n / i == 0 |
n % i == 0 |
判断整除应用取余 %,除法 / 永远不会等于0(n > i时) |
| begin3 |
is_prime num |
is_prime(num) |
函数调用必须加括号包裹参数 |
完整正确代码
| Python |
|---|
| def is_prime(n):
if n < 2:
return False
for i in range(2, n): # ✅ 修正1:从2开始
if n % i == 0: # ✅ 修正2:取余判断整除
return False
return True
num = int(input("请输入一个正整数:"))
if is_prime(num): # ✅ 修正3:函数调用加括号
print(f"{num}是素数")
else:
print(f"{num}不是素数")
# 输入 7 → 输出: 7是素数
# 输入 10 → 输出: 10不是素数
# 输入 1 → 输出: 1不是素数
|
解析:
-
错误1:range(1, n) 从 1 开始,而任何整数都能被 1 整除(n % 1 == 0 恒成立),这会导致所有数都被判为非素数。素数判断应从 2 开始试除:range(2, n)
| Python |
|---|
| # range(1, n) 的遍历过程(以 n=7 为例):
# i=1: 7 % 1 == 0 → True → return False(错误!1能整除所有数)
# range(2, n) 的遍历过程:
# i=2: 7 % 2 == 1 → 不整除
# i=3: 7 % 3 == 1 → 不整除
# i=4: 7 % 4 == 3 → 不整除
# i=5: 7 % 5 == 2 → 不整除
# i=6: 7 % 6 == 1 → 不整除
# 循环结束 → return True(7是素数 ✅)
|
-
错误2:n / i 是除法运算,结果是一个浮点数,几乎永远不会恰好等于 0。判断能否整除应该用取余运算 %:如果 n % i == 0,说明 n 能被 i 整除,n 不是素数
| Python |
|---|
| 7 / 2 # 3.5,不等于0
7 % 2 # 1,不等于0 → 不能整除 ✅
10 / 2 # 5.0,不等于0
10 % 2 # 0,等于0 → 能整除 ✅
|
-
错误3:Python 中函数调用必须用括号包裹参数。is_prime num 是语法错误,正确写法是 is_prime(num)
🔑 知识点:素数判断与运算符
| 运算符 |
含义 |
示例 |
结果 |
/ |
除法 |
7 / 2 |
3.5 |
// |
整除 |
7 // 2 |
3 |
% |
取余 |
7 % 2 |
1 |
- 判断整除:
a % b == 0(a 能被 b 整除)
📖 拓展
| Python |
|---|
| # 优化版:只需检查到 √n
import math
def is_prime_optimized(n):
if n < 2:
return False
for i in range(2, int(math.sqrt(n)) + 1):
if n % i == 0:
return False
return True
# 为什么只需检查到 √n?
# 如果 n = a * b,且 a ≤ b,则 a ≤ √n
# 所以如果 n 有因子,一定有一个 ≤ √n
# 性能对比(判断 1000003 是否为素数):
# range(2, n) → 循环约 100 万次
# range(2, √n+1) → 循环约 1000 次
# 找出 1~100 的所有素数
primes = [n for n in range(2, 101) if is_prime_optimized(n)]
print(primes)
# [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47,
# 53, 59, 61, 67, 71, 73, 79, 83, 89, 97]
|
📌 记忆要点
-
素数判断循环从 2 开始:range(2, n),不是 range(1, n)
-
判断整除用 %(取余),不是 /(除法)
-
函数调用必须加括号:func(arg),不是 func arg
第5题:字符统计
题目: 统计字符串中大写字母、小写字母和数字的个数。
| Python |
|---|
| s = "Hello World 123!"
upper_count = 0
lower_count = 0
digit_count = 0
for ch in s:
#**********begin1**********
if ch.isupper # ❌ 错误1
upper_count += 1
elif ch.islower():
lower_count += 1
elif ch.isdigit():
digit_count += 1
#**********end1**********
#**********begin2**********
print("大写字母:" + upper_count + "个,小写字母:" + lower_count + "个,数字:" + digit_count + "个")
#**********end2**********
|
✅ 错误修正
| 错误位置 |
原代码 |
修正后 |
错误原因 |
| begin1 |
ch.isupper |
ch.isupper() |
isupper 是方法,必须加 () 调用;不加括号是方法对象引用,在 if 中恒为 True |
| begin2 |
"大写字母:" + upper_count + "个" |
f"大写字母:{upper_count}个..." 或 "大写字母:" + str(upper_count) + "个" |
upper_count 等是整数,不能与字符串直接拼接 |
完整正确代码
| Python |
|---|
| s = "Hello World 123!"
upper_count = 0
lower_count = 0
digit_count = 0
for ch in s:
if ch.isupper(): # ✅ 修正1:加括号调用方法
upper_count += 1
elif ch.islower():
lower_count += 1
elif ch.isdigit():
digit_count += 1
print(f"大写字母:{upper_count}个,小写字母:{lower_count}个,数字:{digit_count}个")
# ✅ 修正2:使用 f-string
# 输出: 大写字母:2个,小写字母:8个,数字:3个
|
解析:
-
错误1:ch.isupper(无括号)是方法对象的引用,不是方法调用。在 if 条件中,方法对象被视为"真值"(truthy),导致条件永远为 True。所有字符都会被判定为大写字母,统计结果错误
| Python |
|---|
| "H".isupper # <built-in method isupper of str object>(方法对象,truthy)
"H".isupper() # True(方法调用,返回布尔值 ✅)
"h".isupper # <built-in method isupper of str object>(同样是方法对象,truthy!)
"h".isupper() # False(方法调用,返回正确结果 ✅)
|
加上 if ch.isupper: 后,所有字符(包括小写字母、数字、空格)都会被判定为"大写",因为方法对象本身是 truthy 的
-
错误2:upper_count、lower_count、digit_count 都是整数,Python 不允许整数与字符串用 + 拼接。解决方案:
- f-string:
f"大写字母:{upper_count}个"(推荐,简洁清晰)
str() 转换:"大写字母:" + str(upper_count) + "个"
🔑 知识点:字符串判断方法
| 方法 |
功能 |
示例 |
isupper() |
是否全为大写 |
"ABC".isupper() → True |
islower() |
是否全为小写 |
"abc".islower() → True |
isdigit() |
是否全为数字 |
"123".isdigit() → True |
isalpha() |
是否全为字母 |
"abc".isalpha() → True |
isalnum() |
是否为字母或数字 |
"abc123".isalnum() → True |
isspace() |
是否为空白字符 |
" ".isspace() → True |
- 方法调用必须加括号:
ch.isupper → 方法对象(truthy,始终为 True)
ch.isupper() → 方法调用(返回 True/False)
📖 拓展
| Python |
|---|
| # 方法2:使用字符串方法配合 sum()
s = "Hello World 123!"
upper_count = sum(1 for ch in s if ch.isupper())
lower_count = sum(1 for ch in s if ch.islower())
digit_count = sum(1 for ch in s if ch.isdigit())
print(f"大写:{upper_count},小写:{lower_count},数字:{digit_count}")
# 方法3:ASCII 码判断(不推荐,可读性差)
for ch in s:
if 65 <= ord(ch) <= 90: # A-Z
upper_count += 1
elif 97 <= ord(ch) <= 122: # a-z
lower_count += 1
elif 48 <= ord(ch) <= 57: # 0-9
digit_count += 1
# 方法4:统计所有字符类型
s = "Hello World 123!"
for ch in s:
if ch.isupper():
print(f"'{ch}' → 大写字母")
elif ch.islower():
print(f"'{ch}' → 小写字母")
elif ch.isdigit():
print(f"'{ch}' → 数字")
else:
print(f"'{ch}' → 其他字符")
|
📌 记忆要点
-
字符串判断方法必须加 () 调用:ch.isupper() 不是 ch.isupper
-
不加括号得到的是方法对象,在 if 中恒为 True
-
整数与字符串拼接用 f-string:f"数量:{count}"
第6题:斐波那契数列
题目: 生成前n个斐波那契数并存入列表返回。
| Python |
|---|
| def fibonacci(n):
if n <= 0:
return []
if n == 1:
return [1]
fib = [1, 1]
#**********begin1**********
for i in range(2, n - 1): # ❌ 错误1
#**********end1**********
#**********begin2**********
fib.add(fib[i-1] + fib[i-2]) # ❌ 错误2
#**********end2**********
return fib
#**********begin3**********
result = fibonacci 10 # ❌ 错误3
#**********end3**********
print(result)
|
✅ 错误修正
| 错误位置 |
原代码 |
修正后 |
错误原因 |
| begin1 |
range(2, n - 1) |
range(2, n) |
n-1 少生成了一个数,列表只有 n-1 个元素,应为 n 个 |
| begin2 |
fib.add(...) |
fib.append(...) |
列表没有 add 方法,添加元素应使用 append |
| begin3 |
fibonacci 10 |
fibonacci(10) |
函数调用必须用括号包裹参数 |
完整正确代码
| Python |
|---|
| def fibonacci(n):
if n <= 0:
return []
if n == 1:
return [1]
fib = [1, 1]
for i in range(2, n): # ✅ 修正1:range(2, n)
fib.append(fib[i-1] + fib[i-2]) # ✅ 修正2:append 方法
return fib
result = fibonacci(10) # ✅ 修正3:函数调用加括号
print(result)
# 输出: [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
|
解析:
-
错误1:range(2, n-1) 生成 2 到 n-2 的整数,只有 n-3 次循环。列表初始有 2 个元素 [1, 1],再添加 n-3 个,总共 n-1 个元素,但题目要求 n 个。range(2, n) 生成 2 到 n-1 的整数,循环 n-2 次,总共 2 + (n-2) = n 个元素
| Python |
|---|
| # n=10 时:
# range(2, 9) → i = 2,3,4,5,6,7,8 → 循环7次 → 列表9个元素 ❌
# range(2, 10) → i = 2,3,4,5,6,7,8,9 → 循环8次 → 列表10个元素 ✅
|
-
错误2:列表(list)没有 add 方法,添加元素应使用 append 方法。add 是集合(set)的方法
| Python |
|---|
| fib = [1, 1]
fib.append(2) # 列表添加元素 ✅ → [1, 1, 2]
fib.add(2) # AttributeError: 'list' object has no attribute 'add'
# set 使用 add
s = {1, 2}
s.add(3) # 集合添加元素 ✅ → {1, 2, 3}
|
-
错误3:Python 中函数调用必须用括号包裹参数。fibonacci 10 会被解释为引用 fibonacci 函数对象然后跟一个 10,这是语法错误。正确写法是 fibonacci(10)
🔑 知识点:range 与列表方法
range(start, stop) 的范围是 [start, stop),即包含 start,不包含 stop
| 代码 |
生成的序列 |
元素个数 |
range(2, n-1) |
2, 3, ..., n-2 |
n-3 个 |
range(2, n) |
2, 3, ..., n-1 |
n-2 个 |
| 类型 |
添加方法 |
示例 |
列表 list |
append(item) |
lst.append(3) → 末尾添加 |
列表 list |
insert(i, item) |
lst.insert(0, 3) → 指定位置插入 |
集合 set |
add(item) |
s.add(3) → 添加元素 |
- 斐波那契数列:每一项等于前两项之和
- F(1)=1, F(2)=1, F(3)=2, F(4)=3, F(5)=5, ...
📖 拓展
| Python |
|---|
| # 方法2:生成器(节省内存)
def fib_generator(n):
a, b = 1, 1
for _ in range(n):
yield a
a, b = b, a + b
print(list(fib_generator(10)))
# [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
# 方法3:递归(效率低,仅适合学习)
def fib_recursive(n):
if n <= 2:
return 1
return fib_recursive(n-1) + fib_recursive(n-2)
# 方法4:列表推导式配合动态规划
def fib_dp(n):
fib = [0, 1]
for i in range(2, n + 1):
fib.append(fib[i-1] + fib[i-2])
return fib[1:] # 去掉开头的 0
print(fib_dp(10))
# [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
|
📌 记忆要点
-
range(2, n) 包含 2,不包含 n;注意 n-1 的 off-by-one 错误
-
列表添加用 append(),集合添加用 add(),不要混淆
-
函数调用必须加括号:func(arg),不是 func arg
第7题:学生信息类
题目: 定义学生类,按成绩从高到低排序后输出每位学生的信息。
| Python |
|---|
| class Student:
#**********begin1**********
def _init_(self, name, score): # ❌ 错误1
#**********end1**********
self.name = name
self.score = score
def info(self):
#**********begin2**********
return self.name + "的成绩为:" + self.score # ❌ 错误2
#**********end2**********
students = [
Student("张三", 85),
Student("李四", 92),
Student("王五", 78)
]
#**********begin3**********
students.sort(key=lambda s: s.score) # ❌ 错误3
#**********end3**********
for s in students:
print(s.info())
|
✅ 错误修正
| 错误位置 |
原代码 |
修正后 |
错误原因 |
| begin1 |
def _init_ |
def __init__ |
构造方法必须用双下划线 __init__,单下划线 _init_ 不是特殊方法 |
| begin2 |
+ self.score |
+ str(self.score) 或 f"..." |
self.score 是 int,不能与 str 直接拼接 |
| begin3 |
key=lambda s: s.score |
key=lambda s: s.score, reverse=True |
默认升序,题目要求降序需加 reverse=True |
完整正确代码
| Python |
|---|
| class Student:
def __init__(self, name, score): # ✅ 修正1:双下划线 __init__
self.name = name
self.score = score
def info(self):
return f"{self.name}的成绩为:{self.score}" # ✅ 修正2:f-string
students = [
Student("张三", 85),
Student("李四", 92),
Student("王五", 78)
]
students.sort(key=lambda s: s.score, reverse=True) # ✅ 修正3:降序排序
for s in students:
print(s.info())
# 输出:
# 李四的成绩为:92
# 张三的成绩为:85
# 王五的成绩为:78
|
解析:
-
错误1:_init_ 使用的是单下划线,这不是 Python 的特殊方法名。Python 的构造方法必须命名为 __init__(双下划线),在创建对象时会自动调用。使用 _init_ 不会自动调用,导致 Student("张三", 85) 报 TypeError
| Python |
|---|
| # 单下划线:普通方法,不会自动调用
def _init_(self, name, score): # ❌ 创建对象时不会执行
...
# 双下划线:构造方法,创建对象时自动调用
def __init__(self, name, score): # ✅ 创建对象时自动执行
...
|
-
错误2:self.score 是整数(int),self.name 是字符串(str),Python 中 str + int 会报 TypeError。需要将 self.score 转为字符串:
- f-string:
f"{self.name}的成绩为:{self.score}"(推荐)
str() 转换:self.name + "的成绩为:" + str(self.score)
-
错误3:sort(key=lambda s: s.score) 默认按 score 升序排列(从低到高),输出为"王五78、张三85、李四92"。题目要求从高到低排序,需要加 reverse=True
🔑 知识点:类定义与排序
- Python 特殊方法使用双下划线(dunder 方法):
| 方法 |
用途 |
调用时机 |
__init__ |
构造方法 |
创建对象时 |
__str__ |
字符串表示 |
print(obj) / str(obj) |
__repr__ |
详细表示 |
交互式输出 / repr(obj) |
__len__ |
长度 |
len(obj) |
__lt__ |
小于比较 |
obj1 < obj2 |
sort() / sorted() 参数:
key:排序依据函数
reverse:True 为降序,False 为升序(默认)
| Python |
|---|
| # 升序(默认)
students.sort(key=lambda s: s.score)
# 降序
students.sort(key=lambda s: s.score, reverse=True)
|
📖 拓展
| Python |
|---|
| # 方法2:实现 __lt__ 方法,让对象可直接比较
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __lt__(self, other):
return self.score > other.score # 降序:大于时返回True
def __str__(self):
return f"{self.name}的成绩为:{self.score}"
students = [Student("张三", 85), Student("李四", 92), Student("王五", 78)]
students.sort() # 直接排序,无需 key 和 reverse
for s in students:
print(s)
# 方法3:使用 __str__ 简化输出
class Student:
def __init__(self, name, score):
self.name = name
self.score = score
def __str__(self):
return f"{self.name}的成绩为:{self.score}"
students = [Student("张三", 85), Student("李四", 92), Student("王五", 78)]
for s in sorted(students, key=lambda s: s.score, reverse=True):
print(s)
|
📌 记忆要点
-
构造方法:__init__(双下划线),不是 _init_
-
字符串与整数拼接:用 f-string 或 str() 转换
-
降序排序:sort(key=..., reverse=True)
第8题:最大公约数
题目: 使用辗转相除法求两个正整数的最大公约数。
| Python |
|---|
| def gcd(a, b):
#**********begin1**********
while b != 0 # ❌ 错误1
#**********end1**********
#**********begin2**********
a, b = b, a / b # ❌ 错误2
#**********end2**********
return a
num1 = 48
num2 = 18
#**********begin3**********
print("最大公约数为:" + gcd(num1, num2)) # ❌ 错误3
#**********end3**********
|
✅ 错误修正
| 错误位置 |
原代码 |
修正后 |
错误原因 |
| begin1 |
while b != 0 |
while b != 0: |
while 语句末尾缺少冒号 |
| begin2 |
a / b |
a % b |
辗转相除法用取余 %,不是除法 / |
| begin3 |
+ gcd(num1, num2) |
+ str(gcd(num1, num2)) 或 f-string |
gcd() 返回整数,不能与字符串直接拼接 |
完整正确代码
| Python |
|---|
| def gcd(a, b):
while b != 0: # ✅ 修正1:添加冒号
a, b = b, a % b # ✅ 修正2:取余运算
return a
num1 = 48
num2 = 18
print(f"最大公约数为:{gcd(num1, num2)}") # ✅ 修正3:f-string
# 输出: 最大公约数为:6
|
解析:
-
错误1:while 语句末尾必须加冒号 :,否则是语法错误。Python 的复合语句(if、elif、else、for、while、def、class 等)都以冒号结尾
| Python |
|---|
| while b != 0 # ❌ 缺少冒号
while b != 0: # ✅ 语法正确
|
-
错误2:辗转相除法(欧几里得算法)的核心是取余运算,不是除法。a, b = b, a % b 的含义是:用 b 替换 a,用 a 除以 b 的余数替换 b,直到余数为 0
| Python |
|---|
| # 辗转相除法求 gcd(48, 18):
# 第1轮:a=48, b=18 → a=18, b=48%18=12
# 第2轮:a=18, b=12 → a=12, b=18%12=6
# 第3轮:a=12, b=6 → a=6, b=12%6=0
# b=0,结束,返回 a=6
# 如果用除法 a/b:
# 第1轮:a=48, b=18 → a=18, b=48/18=2.666...
# 结果是浮点数,永远无法等于0,死循环!
|
-
错误3:gcd(num1, num2) 返回整数 6,"最大公约数为:" + 6 会报 TypeError。需要将整数转为字符串或使用 f-string
🔑 知识点:辗转相除法
-
辗转相除法(欧几里得算法):
- 原理:
gcd(a, b) = gcd(b, a % b),直到 b == 0,此时 a 即为最大公约数
- 时间复杂度:O(log(min(a, b)))
-
Python 中的冒号规则:
| 语句 |
是否需要冒号 |
if ... |
需要 : |
elif ... |
需要 : |
else |
需要 : |
for ... |
需要 : |
while ... |
需要 : |
def ... |
需要 : |
class ... |
需要 : |
%(取余)vs /(除法):
- 取余:
48 % 18 = 12(48除以18的余数)
- 除法:
48 / 18 = 2.666...(48除以18的商)
📖 拓展
| Python |
|---|
| # 方法2:递归实现
def gcd_recursive(a, b):
if b == 0:
return a
return gcd_recursive(b, a % b)
# 方法3:使用 math.gcd(Python 内置)
import math
print(math.gcd(48, 18)) # 6
# 扩展:求最小公倍数 LCM
def lcm(a, b):
return a * b // gcd(a, b)
print(f"GCD: {gcd(48, 18)}") # GCD: 6
print(f"LCM: {lcm(48, 18)}") # LCM: 144
# 关系:GCD * LCM = a * b
# 验证:6 * 144 = 864 = 48 * 18 ✅
# 扩展:求多个数的 GCD
from functools import reduce
nums = [12, 18, 24]
print(reduce(gcd, nums)) # 6
|
第9题:列表过滤
题目: 从列表中筛选出所有偶数,返回新列表并输出。
| Python |
|---|
| def filter_even(lst):
result = []
#**********begin1**********
for num in lst # ❌ 错误1
#**********end1**********
#**********begin2**********
if num % 2 == 1:
result.append(num)
#**********end2**********
#**********begin3**********
return result.sort()
#**********end3**********
nums = [1, 2, 3, 4, 5, 6, 7, 8]
even_nums = filter_even(nums)
print(f"偶数有{len(even_nums)}个:{even_nums}")
|
✅ 错误修正
| 错误位置 |
原代码 |
修正后 |
错误原因 |
| begin1 |
for num in lst |
for num in lst: |
for 语句末尾缺少冒号 |
| begin2 |
num % 2 == 1 |
num % 2 == 0 |
筛选偶数应判断余数为0,== 1 筛选的是奇数 |
| begin3 |
return result.sort() |
return result |
sort() 原地排序并返回 None,不是排序后的列表 |
完整正确代码
| Python |
|---|
| def filter_even(lst):
result = []
for num in lst: # ✅ 修正1:添加冒号
if num % 2 == 0: # ✅ 修正2:余数为0是偶数
result.append(num)
return result # ✅ 修正3:直接返回列表
nums = [1, 2, 3, 4, 5, 6, 7, 8]
even_nums = filter_even(nums)
print(f"偶数有{len(even_nums)}个:{even_nums}")
# 输出: 偶数有4个:[2, 4, 6, 8]
|
解析:
-
错误1:for 语句末尾必须加冒号 :,这是 Python 的语法要求,与 while、if 等语句一致
| Python |
|---|
| for num in lst # ❌ 缺少冒号
for num in lst: # ✅ 语法正确
|
-
错误2:偶数的定义是能被 2 整除的数,即 num % 2 == 0。num % 2 == 1 判断的是奇数,会把奇数添加到结果列表中,与题目要求相反
| Python |
|---|
| # 偶数判断
4 % 2 # 0 → 偶数 ✅
3 % 2 # 1 → 奇数
# 判断偶数:num % 2 == 0
# 判断奇数:num % 2 == 1
|
-
错误3:list.sort() 是原地排序方法,它会修改列表本身并返回 None,不会返回排序后的新列表。return result.sort() 等同于 return None
| Python |
|---|
| lst = [3, 1, 2]
lst.sort() # 原地排序,lst 变为 [1, 2, 3],返回 None
print(lst) # [1, 2, 3]
lst = [3, 1, 2]
result = lst.sort() # result = None ❌
result = sorted(lst) # result = [1, 2, 3] ✅
|
本题中偶数列表 [2, 4, 6, 8] 已经是有序的,不需要排序,直接 return result 即可
🔑 知识点:列表排序与奇偶判断
| 方法 |
是否原地修改 |
返回值 |
用法 |
lst.sort() |
是,修改原列表 |
None |
lst.sort() → 列表变为排序后的 |
sorted(lst) |
否,返回新列表 |
排序后的新列表 |
new = sorted(lst) → 原列表不变 |
-
奇偶判断:
- 偶数:
num % 2 == 0(能被 2 整除)
- 奇数:
num % 2 == 1(除以 2 余 1)
-
常见 sort() 返回 None 的陷阱:
| Python |
|---|
| # ❌ 错误:sort() 返回 None
result = my_list.sort()
# ✅ 正确写法1:先排序再返回
my_list.sort()
return my_list
# ✅ 正确写法2:使用 sorted()
return sorted(my_list)
|
📖 拓展
| Python |
|---|
| # 方法2:列表推导式(推荐,简洁高效)
def filter_even_v2(lst):
return [num for num in lst if num % 2 == 0]
# 方法3:filter 函数
def filter_even_v3(lst):
return list(filter(lambda x: x % 2 == 0, lst))
# 方法4:同时筛选奇偶
nums = [1, 2, 3, 4, 5, 6, 7, 8]
evens = [n for n in nums if n % 2 == 0]
odds = [n for n in nums if n % 2 == 1]
print(f"偶数:{evens}") # [2, 4, 6, 8]
print(f"奇数:{odds}") # [1, 3, 5, 7]
# 方法5:按条件分组
from collections import defaultdict
groups = defaultdict(list)
for n in nums:
groups["偶数" if n % 2 == 0 else "奇数"].append(n)
print(dict(groups)) # {'奇数': [1, 3, 5, 7], '偶数': [2, 4, 6, 8]}
|
📌 记忆要点
-
for、while、if 等语句末尾必须加冒号 :
-
偶数判断:num % 2 == 0,奇数判断:num % 2 == 1
-
sort() 原地排序返回 None,sorted() 返回新列表
-
不要写 return lst.sort(),应该 return lst 或 return sorted(lst)
第10题:阶乘计算
题目: 计算并输出输入正整数的阶乘。
| Python |
|---|
| def factorial(n):
#**********begin1**********
result = 0 # ❌ 错误1
#**********end1**********
#**********begin2**********
for i in range(1, n): # ❌ 错误2
#**********end2**********
result *= i
return result
n = int(input("请输入一个正整数:"))
#**********begin3**********
print(str(n) + "的阶乘为:" + factorial(n)) # ❌ 错误3
#**********end3**********
|
✅ 错误修正
| 错误位置 |
原代码 |
修正后 |
错误原因 |
| begin1 |
result = 0 |
result = 1 |
累乘初始值应为1,0乘以任何数都为0 |
| begin2 |
range(1, n) |
range(1, n + 1) |
range(1, n) 不包含 n,少乘了 n |
| begin3 |
+ factorial(n) |
+ str(factorial(n)) 或 f-string |
factorial() 返回整数,不能与字符串直接拼接 |
完整正确代码
| Python |
|---|
| def factorial(n):
result = 1 # ✅ 修正1:初始值为1
for i in range(1, n + 1): # ✅ 修正2:range(1, n+1) 包含n
result *= i
return result
n = int(input("请输入一个正整数:"))
print(f"{n}的阶乘为:{factorial(n)}") # ✅ 修正3:f-string
# 输入 5 → 输出: 5的阶乘为:120
# 输入 6 → 输出: 6的阶乘为:720
# 输入 10 → 输出: 10的阶乘为:3628800
|
解析:
-
错误1:阶乘是连乘运算,初始值必须为 1。result = 0 会导致 result *= i 始终为 0,因为 0 乘以任何数都等于 0
| Python |
|---|
| # 阶乘计算过程(n=5):
# 正确:result = 1
# 1 * 1 = 1 → 1 * 2 = 2 → 2 * 3 = 6 → 6 * 4 = 24 → 24 * 5 = 120 ✅
# 错误:result = 0
# 0 * 1 = 0 → 0 * 2 = 0 → 0 * 3 = 0 → ... → 永远是0 ❌
|
累加运算初始值为 0,累乘运算初始值为 1,这是基本原则
-
错误2:range(1, n) 生成 1 到 n-1 的整数,不包含 n。阶乘 n! = 1 * 2 * 3 * ... * n,必须包含 n。应改为 range(1, n + 1)
| Python |
|---|
| # n=5 时:
# range(1, 5) → 1, 2, 3, 4 → 结果 = 24(少乘了5)❌
# range(1, 6) → 1, 2, 3, 4, 5 → 结果 = 120 ✅
|
-
错误3:factorial(n) 返回整数,"的阶乘为:" + 120 会报 TypeError。需要转为字符串或使用 f-string
🔑 知识点:累乘与 range
| 运算 |
初始值 |
示例 |
累加 += |
0 |
total = 0; total += x |
累乘 *= |
1 |
product = 1; product *= x |
range(start, stop) 的范围是 [start, stop),不包含 stop
| 代码 |
生成的数 |
说明 |
range(1, 5) |
1, 2, 3, 4 |
不包含 5 |
range(1, 6) |
1, 2, 3, 4, 5 |
包含 5 |
📖 拓展
| Python |
|---|
| # 方法2:递归实现阶乘
def factorial_recursive(n):
if n <= 1:
return 1
return n * factorial_recursive(n - 1)
# 方法3:使用 math.factorial(Python 内置)
import math
print(math.factorial(5)) # 120
# 方法4:reduce 函数
from functools import reduce
def factorial_reduce(n):
return reduce(lambda x, y: x * y, range(1, n + 1), 1)
# 阶乘增长速度
# 1! = 1
# 5! = 120
# 10! = 3628800
# 20! = 2432902008176640000
# Python 支持任意大整数,不会溢出
# 阶乘的常见应用:排列组合
# 排列数 A(n,m) = n! / (n-m)!
# 组合数 C(n,m) = n! / (m! * (n-m)!)
def combination(n, m):
return math.factorial(n) // (math.factorial(m) * math.factorial(n - m))
print(f"C(5,2) = {combination(5, 2)}") # C(5,2) = 10
|
📌 记忆要点
-
累乘初始值为 1,累加初始值为 0
-
range(1, n) 不包含 n,要包含 n 需写 range(1, n + 1)
-
整数与字符串拼接用 f-string 或 str() 转换