目录
1. 深拷贝与浅拷贝
1.1 什么是浅拷贝
- 只复制对象的顶层结构,不会递归复制内部嵌套的子对象
- 子对象(列表/字典/自定义对象)仍然共用同一个内存引用
- Python 中
list.copy()、字典copy()、切片[:]、copy.copy()都是浅拷贝
1.2 什么是深拷贝
- 递归复制对象所有层级的嵌套结构
- 新对象与原对象完全独立,修改互不影响
- 使用
copy.deepcopy()实现
1.3 典型现象
- 浅拷贝:修改嵌套子对象(如列表里的列表),原对象同步被修改
- 深拷贝:新对象与原对象完全隔离,互不干扰
1.4 如何排查
- 使用
id()函数查看内存地址 - 地址相同 = 同一个对象 = 浅拷贝
- 地址不同 = 独立对象 = 深拷贝
1.5 解决方案
- 简单独立拷贝:浅拷贝
copy() - 嵌套对象、完全独立:必须用
copy.deepcopy()
1.6 面试扩展(必背)
- 不可变对象(str/int/tuple):浅拷贝=深拷贝效果
- 深拷贝会降低性能,只在必要时使用
- 函数传参是引用传递,容易踩浅拷贝坑
2. 垃圾回收机制 GC
2.1 什么是垃圾回收
Python 自动回收不再被使用的内存空间,避免内存泄漏、OOM
2.2 核心机制(三合一)
- 引用计数(主)
- 每个对象维护引用计数
- 计数=0 → 立即回收
- 标记清除
- 解决循环引用问题(列表互相引用、对象互相引用)
- 遍历所有对象,标记存活→清除未标记
- 分代回收
- 新生代、中年代、老年代
- 存活越久,回收频率越低,提升效率
2.3 异常现象
- 内存占用持续上涨
- 程序运行越来越慢
- 最终出现 OOM 进程崩溃
2.4 如何排查
gc模块查看回收状态objgraph分析对象引用链- 日志监控内存占用
2.5 解决方案
- 避免循环引用
- 手动
del删除临时大对象 - 使用
weakref弱引用 - 函数执行完毕自动释放局部变量
2.6 面试扩展
- 引用计数简单高效,但无法解决循环引用
- 垃圾回收会带来短暂性能消耗
- 大内存项目必须注意:缓存、连接、大列表的及时释放
3. 闭包
3.1 什么是闭包
满足三个条件:
- 函数嵌套定义
- 内部函数引用外部函数的变量
- 外部函数返回内部函数
3.2 闭包的作用
- 保留外部函数变量状态(不销毁)
- 实现装饰器的底层基础
- 封装私有变量、实现数据隐藏
- 实现工厂函数、回调函数携带状态
3.3 闭包现象
- 外部函数执行完毕后,内部变量依然存活
- 多次调用内部函数,可持续访问/修改状态
3.4 面试扩展
- 闭包变量修改必须用
nonlocal声明 - 闭包=携带状态的函数
- 装饰器 = 闭包的经典应用
- 常用于:缓存、计数、权限、日志
4. 迭代器 / 生成器 / 协程 区别
4.1 迭代器
- 实现
__iter__+__next__的对象 - 统一遍历协议
- 只能从头到尾遍历一次
- 例子:
iter()、文件对象、map/zip
4.2 生成器
- 带
yield的函数 - 惰性计算:用到才生成,不占大量内存
- 处理大文件、大数据流必备
- 本质是迭代器的语法糖
4.3 协程
async def+await- 用户态轻量级线程
- 遇到 IO 自动切换,不阻塞
- 支持高并发网络请求、数据库操作
4.4 核心区别(面试必背)
- 迭代器:统一遍历
- 生成器:节省内存,惰性生成
- 协程:高并发 IO,非阻塞
4.5 适用场景
- 大文件读取 → 生成器
- 千万级数据遍历 → 生成器
- 网络请求/数据库 → 协程
- 通用遍历 → 迭代器
5. Python 高级扩展知识点(面试官必问)
5.1 装饰器
- 不修改原函数,增强功能
- 应用:日志、权限、缓存、重试、计时
- 必须用
@functools.wraps保留原函数信息 - 支持:带参数装饰器、类装饰器、多装饰器
5.2 GIL 全局解释器锁
- CPython 同一时刻只有一个线程执行字节码
- CPU 密集多线程无法提速
- IO 密集多线程/协程有效
- 突破:多进程、协程、C 扩展
5.3 上下文管理器
with语句- 自动释放资源:文件、锁、连接、线程
- 实现
__enter__+__exit__ - 避免忘记关闭导致泄漏
5.4 异步 IO asyncio
- 单线程并发
- 适合:网络请求、API、DB、爬虫、消息
- 事件循环 + 协程 + 任务
- 不适合 CPU 密集型
5.5 内存泄漏常见原因
- 全局列表无限增长
- 未关闭的数据库/文件连接
- 装饰器/闭包持有大对象
- 缓存不设置过期
- 循环引用
评论区