广州鱼七网络科技 Python 开发实习一面面经(已 OC)
- 轮次
- 一面
- 时间
- 2026-10
- 来源
- 牛客网
《面试题目》
- 自我介绍
- 项目主要实现了哪些功能?
- 详细讲一下你的项目中如何解决上下文过长的问题。
- 讲一下项目中关于面向对象编程思想的应用。
- 项目中是否出现过大量 if-else 的情况?
- 项目中关于单例模式的应用有哪些?
- 项目中是否出现过模块之间循环导入导致的报错,是如何解决的?
- 常见的排序算法有哪些?
- 详细讲一下快速排序。
- 讲一下二分查找的思路。
- 二分查找是如何判定目标不在该数组中的?
- 链表和数组在访问元素和插入元素两种操作上有什么区别?
- 什么是二叉树?完全二叉树其实是哪种数据结构?
- Python 元组和列表有什么区别?
- 讲一下 Python 生成器及其具体应用场景。
- 讲一下 Python 装饰器及其具体应用场景。
- Python 中类方法、静态方法和实例方法有什么区别?
- Python 中实例对象的
__new__与__init__触发顺序是什么? - 讲讲你对 MVC 框架思想的了解。
- 说说你对消息队列的了解。
- 删除长度为 100 的数组中的所有奇数;如果不允许新建数组,要怎么实现?
- 找出整数数组中所有重复数字的下标。
《参考解析》
「上下文过长怎么解决」要答成一整套分层方案。 只说截断会丢信息,只说上向量库又没讲清退化路径。完整答法是四层:先用窗口策略兜底,保留系统提示与最近若干轮,早期内容按重要性淘汰;再做摘要压缩,把历史对话滚动摘要成一段状态,注意摘要本身会累积误差,应定期重写而不是无限叠加;然后是检索注入,把长文档切块建索引,按当前问题召回相关片段,并控制召回条数与去重;最后把任务状态外置,关键结论写成结构化字段,每轮只带状态不带全部历史。回答时补上取舍:摘要省 token 但丢细节,检索更准但多一次调用延迟,工程上通常组合使用,并为不同链路设不同预算。
循环导入的本质是模块初始化顺序被打乱。 执行 import 语句时 Python 会运行目标模块的顶层代码,A 导入 B、B 又导入 A 时,后进入的一方拿到的是尚未执行完的半成品模块。定位方法是看报错栈里的导入顺序,以及报 AttributeError 的那个名字是不是定义在对方模块的后半段。常见修法有四条:把 import 从模块顶层移到函数体内做延迟导入,最省事,适合只在某条分支用到的依赖;把双方共用的部分抽到第三个底层模块,让依赖变成单向;用 TYPE_CHECKING 下的导入只服务类型注解,运行时不引入;以及用依赖注入或接口协议把编译期依赖改成运行期注入。顺带说清 import x 与 from x import y 的差别——后者在导入时就要取属性,遇到循环更容易当场失败。
快排和二分要把边界讲清楚,这两题面试官一定追边界。 快速排序是分治加分区:每轮选基准把数组分成小于和大于两部分再递归,平均 O(n log n)、最坏 O(n²),最坏出现在数组已经有序又固定取端点做基准时,所以工程实现会随机化基准或三数取中,小数组切换插入排序;它原地交换、不稳定,额外空间是递归栈的 O(log n)。二分查找的前提是有序,核心是区间定义前后一致(左闭右闭还是左闭右开),否则就会出现死循环或漏查;判定目标不在数组里的方式是区间收敛到空(lo 越过 hi)后仍未命中,而不是靠某次比较;有重复元素时找左边界要在命中后继续往左收缩,找右边界反之。
链表和数组的区别要落到工程选择上。 数组内存连续,随机访问 O(1),插入删除平均 O(n)(要搬移后续元素),扩容时整块拷贝并可能产生内存碎片;链表节点分散,按下标访问 O(n),已知前驱节点时插入删除 O(1),代价是每个节点额外的指针开销和很差的缓存局部性。实际后端代码里绝大多数场景用动态数组(Python list、切片)更划算,因为遍历和随机访问远比中间插入常见;真正需要频繁头部插入或做 LRU 这类移动操作时,才用链表或双端队列。可以再补一句跳表与平衡树,它们是有序加范围查询需求下的折中。
Python 特性题每条都要带一个真实使用场景。 生成器的价值是惰性求值:yield 把函数变成状态机,逐条产出、只在需要时计算,适合读大文件、流式处理日志和构造无限序列,代价是只能单向遍历一次。装饰器本质是「接收函数、返回函数」的高阶函数加闭包,用于日志、计时、鉴权、缓存、重试这类横切逻辑,实现时要加 functools.wraps 保留元信息,需要带参数的装饰器就再包一层。类方法和实例方法的区别在第一个参数:实例方法收 self 访问对象状态,类方法收 cls,常用于写替代构造器(从配置或字符串创建实例),静态方法两者都不收,只是挂在类命名空间下的普通函数。对象创建顺序是先 __new__ 分配并返回实例、再由 __init__ 初始化,重写 __new__ 主要出现在单例、不可变类型和元类场景。
两道口述算法题先给思路和复杂度,再处理追问。 删除长度 100 的数组里所有奇数,最直接的是新建列表过滤,O(n) 时间、O(n) 空间;不允许新建数组时改用双指针原地覆盖——写指针指向下一个可写位置,读指针扫一遍,遇到偶数就写到写指针并前移,最后返回新的有效长度,后面的元素视为无效,时间 O(n)、额外空间 O(1)。找重复数字的下标,用哈希表记录每个数字首次出现的位置,第二次遇到就把它加入结果,时间 O(n)、空间 O(n);要主动提防「每个元素都用 list.index 再扫一遍」的 O(n²) 写法,并确认题目是否要求下标去重、结果是否按升序输出。