不废话,直接进入正题。今天是Day 99,距离“99天精通Python”这个系列收尾只剩最后一天。我没有选择在最后一天讲什么炫技的冷门语法,而是把时间留给面试题解析(下)——因为我自己在带新人、帮朋友做模拟面试的过程中越来越确定一件事:很多人Python写得挺溜,但一坐到面试官对面就垮掉,问题不是不会写代码,是不会“讲”代码。
面试题这种东西,本质上不是标准答案库,而是一面镜子。它照出来的不只是你对某个知识点的记忆,还有你遇到问题时的思考路径、你写代码的习惯、你对底层机制的理解深度。今天这篇,我挑了六大类在Python面试中反复出现的题,每一道都附上思考链路和回答框架。最后,还有一份攒了98天的毕业感言。
1. 到了第99天,为什么还要聊“面试题”
1.1 从“会用”到“会讲”的转变
很多人在第1天到第50天的时候,学习模式是“看文档—照抄—跑通—下一节”。这种模式应付工具类知识没问题,但面到Python的高级特性时就会露馅。举个例子,一个人如果是照着教程写装饰器,他能跑通 @timer,但当你问他“装饰器在什么时机执行?被装饰函数的 __name__ 为什么变了?能不能给装饰器传参?”他可能就卡住了。
面试题解析(下)这期,我特意选的题目都偏向“第二层”“第三层”问题——第一层是“是什么”,第二层是“为什么”,第三层是“在不同场景下怎么取舍”。这恰好也是面试官常用的追问路径。
1.2 面试题不是标准答案,是思维模型
我在Day 60那篇里提过,学习任何技术都要建立“场景→方案→代价”的思考框架。面试题也一样。背下十道题的标准答案,不如搞懂一道题的完整分析过程。比如面试官问“Python的 dict 为什么查找快?”,如果你只回答“因为底层是哈希表”,那和没答差不多。更完整的回答应该包含三层:
- 哈希函数把键映射为数组下标,平均复杂度O(1)
- 冲突处理方式(Python用的是开放寻址法,而不是Java的链地址法)
- 哈希表扩容、装载因子、哈希随机化这些机制如何影响实际性能
这三层讲完,面试官基本就能判断出你是“背过”还是“真懂”。后面所有题目,我都会按这种思路展开。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Python对象模型与魔法方法:最容易翻车的“基础题”
2.1 __init__和__new__到底谁先执行
基本答法:__new__先执行,负责创建并返回实例对象;__init__后执行,负责初始化实例属性。
完整答法要讲清楚三件事。第一,__new__是静态方法,第一个参数是类本身,返回值通常是该类的一个实例;如果__new__返回的不是本类实例,__init__不会被调用。第二,__init__的第一个参数是实例本身,返回值必须是None,否则会抛TypeError。第三,日常开发中重写__new__最多的场景是单例模式和不可变对象的自定义创建。
比如一个经典的懒汉式单例:
python复制class Singleton:
_instance = None
def __new__(cls, *args, **kwargs):
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
这里有个容易被追问的点:既然__init__在__new__之后执行,单例对象每次构造时__init__是不是也会重复执行?答案是会。所以单例模式如果写在__init__里做初始化,就会出问题。正确的做法是加一个_initialized标记,或者在__new__里完成所有初始化。这种细节题,比单纯背“先new后init”更能拉开差距。
2.2 可变对象与函数默认参数的经典陷阱
这个是Python面试的“送命题”,十个人里至少有六个人栽过。
python复制def append_item(item, items=[]):
items.append(item)
return items
第二次调用时结果会让你大跌眼镜:append_item(1)返回[1],append_item(2)返回[1, 2]。原因在于:函数的默认参数在定义时只被创建一次,之后所有调用共享同一个列表对象。 默认参数如果是可变对象,跨调用会累积状态。
正确写法是:
python复制def append_item(item, items=None):
if items is None:
items = []
items.append(item)
return items
回答这道题时,如果能补充一句“这也是为什么很多开源项目规范里强制要求默认参数不可使用可变对象”,会显得你有工程经验。面试官还会追一个变体:“为什么 None 就可以?”因为None是不可变对象,每次调用时重新赋值一个新的空列表,互相不干扰。
2.3 深拷贝与浅拷贝:从copy模块看内存语义
浅拷贝(copy.copy)只复制最外层容器,内层元素仍然是原对象的引用;深拷贝(copy.deepcopy)会递归复制所有层级。这块如果只是背结论,很容易被追问里的例子击穿。
看这段代码:
p复制
