Python 输出预测测验
「读代码猜输出」是面试和考试最爱考、也最能暴露理解深浅的一关。下面 12 段都能跑,每段都藏着一个让老手也会犹豫的 Python 坑。先在心里算出结果,再点开看对不对。
0 / 12 题已答
第 1 题
调用两次这个函数,第二次打印什么?
def add(x, lst=[]):
lst.append(x)
return lst
print(add(1))
print(add(2))第 2 题
两个内容相同的列表,== 和 is 分别是什么?
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b, a is b)第 3 题
用列表乘法建一个二维网格,改一个格子会怎样?
grid = [[0] * 3] * 3
grid[0][0] = 1
print(grid)第 4 题
循环里造一批 lambda,最后全部调用,输出什么?
funcs = [lambda: i for i in range(3)]
print([f() for f in funcs])第 5 题
对元组里的列表做 +=,会发生什么?
t = ([1, 2],)
try:
t[0] += [3]
except TypeError:
pass
print(t)第 6 题
整除和普通除,负数怎么算?
print(7 // 2, -7 // 2, 7 / 2)第 7 题
字符串的 * 和 + 一起用,谁先算?
print("1" + "2" * 3)第 8 题
and / or 返回的是 True/False 吗?
print(0 or "hello")
print("" and "world")
print(2 or 3)第 9 题
集合去重、以及用 True 和 1 同时当字典键?
s = {1, 2, 2, 3, 3, 3}
d = {True: 'a', 1: 'b'}
print(len(s), len(d), d[1])第 10 题
这个浮点相等判断的结果?
print(0.1 + 0.2 == 0.3)第 11 题
切片和索引越界,会报错吗?
lst = [1, 2, 3]
print(lst[-1], lst[1:99], lst[99:])第 12 题
函数里先打印一个外部变量,再给它赋值,会怎样?
x = 10
def f():
print(x)
x = 20
try:
f()
except UnboundLocalError:
print('错误')答完全部 12 题,看你的逻辑段位 👆
八个最容易翻车的点
- 可变默认参数
- def f(x, lst=[]) 的 [] 只创建一次、跨调用共享。默认值该用 None,函数内再建。
- is vs ==
- == 比值,is 比是否同一对象。判等用 ==;只有和 None 比才用 is。
- 引用而非拷贝
- [[0]*3]*3 三行是同一个列表;list * n 复制的是引用。要独立副本用推导式。
- 闭包延迟绑定
- lambda 里的循环变量调用时才求值,循环结束后全取末值。快照用默认参数 lambda i=i: i。
- // 向下取整
- -7 // 2 = -4(朝负无穷),不是截断的 -3。/ 永远返回 float。
- and/or 返回操作数
- 不返回 True/False,返回其中一个值。x = a or default 靠的就是这个。
- 浮点不能 ==
- 0.1+0.2 != 0.3。比较浮点用 math.isclose 或 abs 差 < 阈值。
- 切片不越界
- 索引越界抛 IndexError,切片越界自动截断到合法范围、不报错。
为什么「读代码猜输出」这么值得练?
| 代码 | 很多人以为 | 实际输出 |
|---|---|---|
| add(1); add(2)(默认 lst=[]) | [1] 和 [2] | [1] 和 [1, 2](共享同一列表) |
| [[0]*3]*3 改一格 | 只改一个格子 | 整列一起变(三行同一引用) |
| [lambda: i for i in range(3)] | [0, 1, 2] | [2, 2, 2](延迟绑定) |
| -7 // 2 | -3(截断) | -4(向下取整) |
| 0.1 + 0.2 == 0.3 | True | False(浮点误差) |
「预测这段代码的输出」是技术面试、计算机考试、刷题网站最高频的一类题——因为它不考你背没背 API,考的是你**到底理解不理解语言的运行机制**:变量是引用还是拷贝?闭包什么时候求值?默认参数何时创建?这些搞懂了,你写的 bug 会少一大半。
上面 12 段代码都能真实运行,覆盖的是 Python 里最经典、最容易让人「我以为……结果不是」的坑:可变默认参数、引用共享、闭包延迟绑定、浮点相等、作用域规则。每一个背后都有一条能迁移到日常写代码的原则。
这些坑不是 Python 的「设计缺陷」,而是它的对象模型和求值规则的**自然推论**——一旦你从「变量是贴在对象上的标签、不是装东西的盒子」这个视角看,大部分行为就顺理成章了。这也是这类题真正训练的东西:从「记住结果」升级到「推得出结果」。
无论你在准备编程面试、备考信息技术/计算机课程,还是刚开始学 Python 想打牢基础——把「读代码猜输出」当日常练习,是把语言从「会用」练到「吃透」最快的路径之一。
想系统补全这套底层理解?喵学堂正在把编程、AI、思维这些「讲人话」的课一门门做出来,每道题都配即时讲解,免注册就能开始。
常见问题
这些题考的是死记硬背吗?
恰恰相反。每道题背后都是一条可推导的规则(引用共享、延迟绑定、向下取整……)。搞懂规则,你就能推出没见过的类似代码的输出,而不是记结果。这也是它比「背语法」有价值的地方。
可变默认参数那题,正确写法是什么?
用 None 当默认值,函数体内再建:`def f(x, lst=None): \n if lst is None: lst = []`。这样每次调用都拿到一个新列表,不会跨调用共享。几乎所有 linter 都会对 `lst=[]` 这种写法报警。
is 和 == 到底什么时候用哪个?
判断「值相等」永远用 ==。`is` 只在判断「是不是同一个对象」时用,最常见的正当场景是 `x is None` / `x is not None`——因为 None 是单例,用 is 判断又快又准。别用 is 去比数字或字符串是否相等,那会踩到缓存的实现细节。
为什么浮点数不能直接用 == 比较?
计算机用有限位二进制存浮点,像 0.1 这种十进制小数无法精确表示,运算会累积微小误差(0.1+0.2 得 0.30000000000000004)。要判等改用 `math.isclose(a, b)`,或自己判 `abs(a-b) < 1e-9`。
这些坑在别的语言里也有吗?
部分有、部分是 Python 特有。「引用而非拷贝」「浮点不精确」几乎所有语言都有;「可变默认参数」「闭包延迟绑定循环变量」是 Python(及部分动态语言)的经典坑;JavaScript 有它自己的一套(var 提升、== 强转、this 绑定)。理解一门语言的坑,本质是理解它的求值模型。