
这一句 for _ in range(int(input())):,它这个是什么意思呢?我们很少看到有这个_占位符
先回答最for _ in range(int(input())):
这一句可以拆成 3 小部分来看:
for _ in range(int(input())):
它的意思其实是:
“先输入一个整数,表示要重复多少次,然后把下面缩进的代码执行这么多次。”
比如输入是:
5
那么这一句就相当于:
“下面的代码循环执行 5 次。”
int(input()) 是什么意思
先看里面这一部分:
input()
作用是:从键盘读入一行内容。
但是 input() 读出来的内容默认是字符串类型,也就是 str。
比如你输入:
5
实际上 input() 得到的是:
'5'
它是字符串,不是整数。
所以要再用 int() 转一下:
int(input())
这样 '5' 就变成了整数 5。
range(int(input())) 是什么意思
假设输入了 5,那么:
range(5)
会生成一个“循环 5 次”的范围,对应的值依次是:
0, 1, 2, 3, 4
所以这句:
for _ in range(5):
就表示循环 5 次。
这个 _ 到底是什么
初学者确实比较少见到这个写法。
_ 本质上也是一个变量名,它不是特殊语法,不是什么占位符关键字。
也就是说,这样写是合法的:
for i in range(5):
print(i)
也同样可以这样写:
for _ in range(5):
print('hello')
区别在于:
i表示“我等会儿可能会用这个循环变量”_表示“这个循环变量我不用,我只是想重复执行几次”
比如这题里,我们只想循环输入学生信息 N 次,但并不关心这是第几次,所以常写成:
for _ in range(int(input())):
意思就是:
“循环若干次,但每次的编号我不需要。”
所以 _ 不是“占位符语法”,而是一种习惯写法
更准确地说:
_只是一个普通变量名- 但程序员约定俗成地把它写成“我不用这个变量”
例如下面两段代码效果一样:
for i in range(3):
name = input()
for _ in range(3):
name = input()
只是第二种更能表达你的意思:
“我只关心循环 3 次,不关心 i 是多少。”
这道题的数据到底是怎么存的
核心点:students = [] 明明是个列表,为什么后面又能 student[0]、student[1] 呢?
关键就在于:students 不是普通的一层列表,而是一个嵌套列表。
也就是:列表里面放的还是列表。
先看最开始这句
students = []
这表示先创建一个空列表。
一开始里面什么都没有:
students = []
每次读入一个学生后,放进去一份 [name, score]
代码是:
name = input()
score = float(input())
students.append([name, score])
假设输入的是:
Harry
37.21
那么这一轮会得到:
name = 'Harry'
score = 37.21
然后执行:
students.append([name, score])
相当于把这个小列表:
['Harry', 37.21]
加入到 students 里面。
此时:
students = [['Harry', 37.21]]
如果继续输入第二个学生呢
再输入:
Berry
37.21
又会加入一个小列表:
['Berry', 37.21]
这时 students 变成:
students = [['Harry', 37.21], ['Berry', 37.21]]
如果再输入:
Tina
37.2
那么就会变成:
students = [['Harry', 37.21], ['Berry', 37.21], ['Tina', 37.2]]
所以 students 的结构到底是什么
你可以把它理解成:
“一个班级名单表,表里的每一行都是一个学生的信息。”
结构像这样:
| students 里面的元素 | 含义 |
|---|---|
['Harry', 37.21] | 一个学生的姓名和分数 |
['Berry', 37.21] | 一个学生的姓名和分数 |
['Tina', 37.2] | 一个学生的姓名和分数 |
所以:
students是“大列表”- 里面每个元素
student是“小列表” - 小列表里有两个内容:姓名、分数
为什么后面可以写 student[0] 和 student[1]
看这段:
for student in students:
scores.append(student[1])
这里的 for student in students 意思是:
“把 students 里的每一个元素依次取出来,临时放到变量 student 中。”
注意:
这里的 student 不是整个 students,它只是 students 里的其中一个元素。
而 students 里的每一个元素本身又是一个列表,比如:
['Harry', 37.21]
那么:
student[0]就是第一个元素,也就是姓名student[1]就是第二个元素,也就是分数
例如当:
student = ['Harry', 37.21]
那么:
student[0] # 'Harry'
student[1] # 37.21
你可以这样理解“外层列表”和“内层列表”
外层列表
students
表示“全班所有学生”。
内层列表
student
表示“某一个学生的这一行数据”。
所以:
students[0]
表示第 1 个学生的整行数据,比如:
['Harry', 37.21]
而:
students[0][0]
表示第 1 个学生的名字:
'Harry'
students[0][1] 表示第 1 个学生的分数:
37.21
用一个最小例子把“存”和“取”完整演示一遍
先存
students = []
students.append(['Harry', 37.21])
students.append(['Berry', 37.21])
students.append(['Tina', 37.2])
print(students)
输出:
[['Harry', 37.21], ['Berry', 37.21], ['Tina', 37.2]]
这说明 students 里装着多个“小列表”。
再取
students = [['Harry', 37.21], ['Berry', 37.21], ['Tina', 37.2]]
print(students[0]) # 第一个学生整行数据
print(students[0][0]) # 第一个学生名字
print(students[0][1]) # 第一个学生分数
输出:
['Harry', 37.21]
Harry
37.21
回到你这道题,整段代码是怎么一步步运行的
原代码:
if __name__ == '__main__':
students = []
for _ in range(int(input())):
name = input()
score = float(input())
students.append([name, score])
scores = []
for student in students:
scores.append(student[1])
second_lowest = sorted(set(scores))[1]
names = []
for student in students:
if student[1] == second_lowest:
names.append(student[0])
names.sort()
for name in names:
print(name)
下面我按执行顺序给你拆开。
第一步:读入学生人数
for _ in range(int(input())):
假设输入:
5
那么表示下面要循环 5 次,也就是要读入 5 个学生的信息。
第二步:把每个学生的信息存到 students 里
每次循环执行:
name = input()
score = float(input())
students.append([name, score])
假设依次输入:
Harry
37.21
Berry
37.21
Tina
37.2
Akriti
41
Harsh
39
循环结束后,students 变成:
[
['Harry', 37.21],
['Berry', 37.21],
['Tina', 37.2],
['Akriti', 41.0],
['Harsh', 39.0]
]
第三步:把所有分数单独取出来
scores = []
for student in students:
scores.append(student[1])
这里每次取出一个学生的小列表。
例如:
- 第一次
student = ['Harry', 37.21] - 第二次
student = ['Berry', 37.21] - 第三次
student = ['Tina', 37.2]
然后 student[1] 就是每个学生的分数。
最后 scores 变成:
[37.21, 37.21, 37.2, 41.0, 39.0]
第四步:找出第二低分
second_lowest = sorted(set(scores))[1]
这句可以拆开理解。
set(scores)
去重。
set([37.21, 37.21, 37.2, 41.0, 39.0])
结果相当于:
{37.2, 37.21, 39.0, 41.0}
sorted(...)
排序后变成列表:
[37.2, 37.21, 39.0, 41.0]
[1]
取排序后的第 2 个元素。
因为下标从 0 开始:
[0]是最低分[1]是第二低分
所以:
second_lowest = 37.21
第五步:找出所有第二低分对应的名字
names = []
for student in students:
if student[1] == second_lowest:
names.append(student[0])
意思是:
遍历每个学生,如果这个学生的分数等于第二低分,就把他的名字加进 names。
最后得到:
['Harry', 'Berry']
第六步:按字母排序名字
names.sort()
排序后:
['Berry', 'Harry']
第七步:一个名字一行输出
for name in names:
print(name)
输出:
Berry
Harry
从思路到代码:这题应该怎么想
这题不要一上来就硬写代码,先想清楚步骤。
第一步先想:我要存什么
每个学生有两项信息:
- 姓名
- 分数
所以一个学生可以存成:
[name, score]
多个学生就可以存成:
students = [
[name1, score1],
[name2, score2],
...
]
第二步再想:我要找什么
题目要找的是:
“第二低分对应的学生姓名”
所以应该先拿到所有分数,找出第二低分,再回头找哪些学生分数等于它。
第三步翻译成代码
先读入并存储:
students = []
for _ in range(int(input())):
name = input()
score = float(input())
students.append([name, score])
再提取所有分数:
scores = []
for student in students:
scores.append(student[1])
再找第二低分:
second_lowest = sorted(set(scores))[1]
再找名字:
names = []
for student in students:
if student[1] == second_lowest:
names.append(student[0])
最后排序输出:
names.sort()
for name in names:
print(name)
常见错误与易混点
1. 把 students 和 student 搞混
这是初学者最容易混的地方。
students:整个学生列表student:其中一个学生的小列表
比如:
for student in students:
这里的 student 不是“所有学生”,只是“当前这一个学生”。
2. 以为 student[0] 是从输入里直接读出来的
不是的。
student[0] 的前提是:student 本身是一个列表,比如:
['Harry', 37.21]
所以才有:
student[0] # 姓名
student[1] # 分数
3. 不理解为什么 [1] 是第二低分
因为排序后下标从 0 开始。
例如:
[37.2, 37.21, 39.0, 41.0]
0号位置:最低分1号位置:第二低分
4. 把 sort() 和 sorted() 用混
这里你前面已经碰到过这个问题了,顺便再强调一下:
names.sort()
是“原地排序”,直接改原列表。
而:
sorted(scores)
是“返回一个新列表”。
这题里两种都能用,但你要知道区别。
一个更直观的“数据结构图”
假设输入完之后:
students = [
['Harry', 37.21],
['Berry', 37.21],
['Tina', 37.2]
]
那么可以把它想成这样:
| 外层位置 | 内层列表内容 | 含义 |
|---|---|---|
students[0] | ['Harry', 37.21] | 第一个学生 |
students[1] | ['Berry', 37.21] | 第二个学生 |
students[2] | ['Tina', 37.2] | 第三个学生 |
继续往里取:
| 表达式 | 结果 | 含义 |
|---|---|---|
students[0][0] | 'Harry' | 第一个学生的名字 |
students[0][1] | 37.21 | 第一个学生的分数 |
students[1][0] | 'Berry' | 第二个学生的名字 |
students[1][1] | 37.21 | 第二个学生的分数 |
最小可运行例子
可以先单独运行这个小例子,专门练“列表里套列表”的存取:
students = []
students.append(['Tom', 80])
students.append(['Alice', 90])
print(students) # 整个列表
print(students[0]) # 第一个学生整行数据
print(students[0][0]) # 第一个学生名字
print(students[0][1]) # 第一个学生分数
运行结果:
[['Tom', 80], ['Alice', 90]]
['Tom', 80]
Tom
80
这个例子看懂了,你对这题的“数据怎么存、怎么取”就会清楚很多。
本节小结
这道题你现在最需要抓住 3 个点。
第一,for _ in range(int(input())): 的意思是:
先输入一个整数 N,然后把下面代码执行 N 次。这里的 _ 只是一个“我不需要这个循环变量”的习惯写法。
第二,students = [] 虽然是列表,但它存进去的每个元素又是一个小列表,所以它是一个“嵌套列表”。
第三,student[0] 和 student[1] 不是在取 students,而是在取“某一个学生的小列表”里的第 1 项和第 2 项:
student[0]是姓名student[1]是分数
你可以把它理解成:students 是“全班名单表”,student 是“其中一行”。
练习
请你自己写一个小程序,不用找第二低分,只做下面这件事:
读入 3 个学生的姓名和分数,存进 students,最后打印:
- 整个
students - 第 1 个学生的名字
- 第 2 个学生的分数
提示
先把每个学生存成:
[name, score]
再把它 append() 到 students 里。
打印第 1 个学生名字时,想一想应该是先取“第几个学生”,还是先取“姓名/分数”。



