
if __name__ == '__main__':
n = int(input())
arr = map(int, input().split())
print(sort(list(set(arr)))[-2])
##这道题这么写,产生这个报错
Traceback (most recent call last):
File "Solution.py", line 5, in <module>
NameError: name 'sort' is not defined
先看这段代码为什么会报错
写的是:
if __name__ == '__main__':
n = int(input())
arr = map(int, input().split())
print(sort(list(set(arr)))[-2])
报错是:
NameError: name 'sort' is not defined
这里的直接原因是:
把 sort 当成了一个可以直接单独调用的函数来写,但 Python 里没有叫 sort() 的内置函数。
Python 里真正存在的是这两个东西:
列表.sort()
sorted(可迭代对象)
也就是说:
sort()不是独立函数sort()是 列表的方法sorted()才是 内置函数
所以这里:
sort(list(set(arr)))
Python 会理解成:“去找一个名字叫 sort 的东西”,但是它根本找不到,于是就报了:
NameError
这道题是干什么的
这道题要找的是“亚军分数”,也就是:
去掉重复分数后,找第二大的那个数。
比如:
2 3 6 6 5
先去重后变成:
2 3 5 6
最大的是 6,第二大的是 5,所以输出 5。
这道题的基本思路
其实已经想到关键步骤了,思路是对的:
- 读入一组数字
- 去重
- 排序
- 取倒数第二个
这正是这道题最常见的写法。
正确写法一:用 sorted()
这是最适合当前阶段直接理解的写法:
if __name__ == '__main__':
n = int(input())
arr = map(int, input().split())
result = sorted(set(arr))
print(result[-2])
这段代码怎么理解
先看这一句:
set(arr)
作用是去重。
原来如果有:
2 3 6 6 5
变成集合后就相当于只保留不同的值。
然后:
sorted(set(arr))
作用是把去重后的结果从小到大排好序,并且返回一个新列表。
所以结果就是:
[2, 3, 5, 6]
最后:
result[-2]
表示取倒数第二个元素,也就是 5。
正确写法二:用 list.sort()
也可以这样写:
if __name__ == '__main__':
n = int(input())
arr = map(int, input().split())
result = list(set(arr))
result.sort()
print(result[-2])
这个写法和上面的区别在于:
sorted(...)是“排完后返回新列表”result.sort()是“直接把result自己排好”
sort() 和 sorted() 的区别
这是这次真正想弄懂的重点。
一句话先讲清楚
sort() 是 列表自己的排序方法。sorted() 是 Python 提供的排序函数。
对比表
| 对比点 | list.sort() | sorted() |
|---|---|---|
| 类型 | 列表方法 | 内置函数 |
| 适用对象 | 只能用于列表 | 可用于列表、元组、字符串、集合等可迭代对象 |
| 是否返回新结果 | 不返回新列表,返回 None | 返回一个新的排好序的列表 |
| 是否改变原数据 | 会直接修改原列表 | 不会修改原对象 |
最容易混淆的一点:为什么不能写进 print 里
很多初学者会这样写:
print(result.sort())
这也是错的。
因为:
result.sort()
虽然确实会把 result 排好序,但它的返回值是:
None
所以这句代码实际相当于:
print(None)
比如:
nums = [3, 1, 2]
print(nums.sort())
输出不是排序后的列表,而是:
None
正确写法应该是:
nums = [3, 1, 2]
nums.sort()
print(nums)
或者直接:
print(sorted(nums))
从思路到代码:这道题到底怎么翻译成程序
我们把人的思考过程慢慢翻译成代码。
第一步:我需要读入分数
arr = map(int, input().split())
这句的意思是:
input()读一整行.split()按空格切开map(int, ...)把每一项从字符串变成整数
比如输入:
2 3 6 6 5
就会得到一串整数。
第二步:我不想让重复的最高分干扰结果
因为如果不去重:
[2, 3, 6, 6, 5]
排序后是:
[2, 3, 5, 6, 6]
倒数第二个还是 6,这就错了。
所以要先去重:
set(arr)
得到类似:
{2, 3, 5, 6}
第三步:我要找到第二大的数
最直接的方法就是排序:
sorted(set(arr))
结果变成:
[2, 3, 5, 6]
然后取倒数第二个:
[-2]
最小可运行例子
下面这份代码最适合你现在记忆:
if __name__ == '__main__':
n = int(input())
arr = map(int, input().split())
nums = sorted(set(arr))
print(nums[-2])
如果专门练 sort() 和 sorted(),可以看这个小例子
例子 1:sort()
nums = [3, 1, 2]
nums.sort()
print(nums)
输出:
[1, 2, 3]
这里是“原地排序”。
例子 2:sorted()
nums = [3, 1, 2]
new_nums = sorted(nums)
print(nums)
print(new_nums)
输出:
[3, 1, 2]
[1, 2, 3]
这里可以看出:
- 原列表
nums没变 sorted(nums)返回了一个新列表
常见错误与易混点
1. 把 sort 当成普通函数写
错误写法:
sort(nums)
正确写法:
nums.sort()
或者:
sorted(nums)
2. 把 sort() 写进 print() 里
错误写法:
print(nums.sort())
因为 sort() 返回的是 None。
正确写法:
nums.sort()
print(nums)
3. 忘了先去重
如果直接排序:
nums = [2, 3, 6, 6, 5]
print(sorted(nums)[-2])
输出会是:
6
这不是亚军分数,因为题目要的是“第二高的不同分数”。
所以必须先:
set(nums)
4. 以为 set 排序后还是原顺序
集合 set 的重点是去重,不保证原顺序。
所以去重后如果要取第二大,一般还要再排序。
本节小结
你这次报错的根本原因不是题目思路错了,而是把 sort() 和 sorted() 混用了。
记住这两句就够了:
list.sort():给列表本身排序。sorted(x):返回一个排好序的新列表。
所以这题最推荐你先记这版:
if __name__ == '__main__':
n = int(input())
arr = map(int, input().split())
print(sorted(set(arr))[-2])
练习
把下面这个列表中的“第二大不同数字”打印出来:
scores = [4, 9, 1, 9, 7, 4]
提示:
先想这三步:
- 去重
- 排序
- 取倒数第二个



