python面试重在理解特性、设计与调试思维,高频题聚焦可变默认参数陷阱、is/==区别、生成器实现及gil真实场景应用。

Python面试题不考死记硬背,重在考察对语言特性的理解、代码设计意识和调试思维。高频题看似简单,但容易在边界处理、性能意识或底层逻辑上暴露短板。下面聚焦几类真题,讲清楚“为什么这么答”和“怎么想到的”。
一、可变对象作为函数默认参数的陷阱
题目常以如下代码开场:
def add_item(item, lst=[]):
lst.append(item)
return lst
<p>print(add_item(1)) # [1]
print(add_item(2)) # [1, 2] ← 意外!问题本质不是“怎么改”,而是“为什么错”。关键点在于:默认参数在函数定义时只初始化一次,可变对象(如 list、dict)会被所有后续调用共享。第二次调用时,用的仍是第一次创建的那个 list。
- ✅ 正确写法:用 None 作默认值,在函数体内初始化
- ✅ 理解延伸:不可变对象(如 int、str、None)没这问题,因为赋值会绑定新对象;而 append 是原地修改
- ✅ 验证技巧:打印 id(lst) 就能看到两次调用是否指向同一内存地址
二、“is” 和 “==” 的区别不能只背定义
很多候选人能说出“is 比较身份,== 比较值”,但遇到实际题仍出错,比如:
立即学习“Python免费学习笔记(深入)”;
抖猫高清去水印微信小程序,源码为短视频去水印微信小程序全套源码,包含微信小程序端源码,服务端后台源码,支持某音、某手、某书、某站短视频平台去水印,提供全套的源码,实现功能包括:1、小程序登录授权、获取微信头像、获取微信用户2、首页包括:流量主已经对接、去水印连接解析、去水印操作指导、常见问题指引3、常用工具箱:包括视频镜头分割(可自定义时长分割)、智能分割(根据镜头自动分割)、视频混剪、模糊图片高
a = 257 b = 257 print(a is b) # False?还是 True?
答案是 False(在交互式环境或普通脚本中)。原因在于:CPython 对小整数(-5 到 256)做了缓存优化,超出范围后每次字面量都会新建对象。所以 257 is 257 在某些上下文(如单行语句)可能为 True,但不可依赖。
- ✅ 原则:判断相等用 ==,判断是否为同一对象(如单例、None 检查)才用 is
- ✅ 特殊安全用法:if x is None 而不是 if x == None
- ✅ 陷阱提醒:“字符串驻留”也有类似行为(如 'hello' is 'hello' 通常为 True),但受编译器优化影响,不保证跨环境一致
三、生成器与迭代器的现场手写能力
面试官常让手写一个带状态的生成器,例如:“实现一个 countdown 类,支持 for 循环,且能多次遍历”。错误答案常写成返回 list,或误用 __iter__ + yield 混搭。
- ✅ 正确思路:生成器函数(含 yield)每次调用都返回新生成器对象,天然支持多次遍历
- ✅ 关键细节:不要在类里直接写 yield,而应定义一个生成器方法,再在 __iter__ 中调用它
- ✅ 示例核心:
class Countdown:
def __init__(self, start):
self.start = start
<pre class='brush:python;toolbar:false;'>def __iter__(self):
n = self.start
while n > 0:
yield n
n -= 1这样每次 for c in Countdown(3): 都获得独立迭代器,互不影响。
四、GIL 与多线程/多进程的真实适用场景
被问“Python 多线程有用吗”,答“没用因为 GIL”是减分项。GIL 只限制同一时刻只有一个线程执行 Python 字节码,但它不影响系统调用(如文件读写、网络请求、time.sleep)期间的线程切换。
- ✅ CPU 密集型任务:用 multiprocessing,避免 GIL 竞争
- ✅ IO 密集型任务:threading 完全可用,甚至更轻量(如并发请求多个 API)
- ✅ 实用建议:用 concurrent.futures 模块统一接口,ThreadPoolExecutor / ProcessPoolExecutor 切换成本低
- ✅ 补充事实:C 扩展(如 numpy 计算、正则匹配)在执行时会释放 GIL,此时多线程也能提升 CPU 利用率









