面灵AI→

广州鱼七网络科技 Python 开发实习一面面经(已 OC)

轮次
一面
时间
2026-10
来源
牛客网

《面试题目》

  1. 自我介绍
  2. 项目主要实现了哪些功能?
  3. 详细讲一下你的项目中如何解决上下文过长的问题。
  4. 讲一下项目中关于面向对象编程思想的应用。
  5. 项目中是否出现过大量 if-else 的情况?
  6. 项目中关于单例模式的应用有哪些?
  7. 项目中是否出现过模块之间循环导入导致的报错,是如何解决的?
  8. 常见的排序算法有哪些?
  9. 详细讲一下快速排序。
  10. 讲一下二分查找的思路。
  11. 二分查找是如何判定目标不在该数组中的?
  12. 链表和数组在访问元素和插入元素两种操作上有什么区别?
  13. 什么是二叉树?完全二叉树其实是哪种数据结构?
  14. Python 元组和列表有什么区别?
  15. 讲一下 Python 生成器及其具体应用场景。
  16. 讲一下 Python 装饰器及其具体应用场景。
  17. Python 中类方法、静态方法和实例方法有什么区别?
  18. Python 中实例对象的 __new__ 与 __init__ 触发顺序是什么?
  19. 讲讲你对 MVC 框架思想的了解。
  20. 说说你对消息队列的了解。
  21. 删除长度为 100 的数组中的所有奇数;如果不允许新建数组,要怎么实现?
  22. 找出整数数组中所有重复数字的下标。

《参考解析》

「上下文过长怎么解决」要答成一整套分层方案。 只说截断会丢信息,只说上向量库又没讲清退化路径。完整答法是四层:先用窗口策略兜底,保留系统提示与最近若干轮,早期内容按重要性淘汰;再做摘要压缩,把历史对话滚动摘要成一段状态,注意摘要本身会累积误差,应定期重写而不是无限叠加;然后是检索注入,把长文档切块建索引,按当前问题召回相关片段,并控制召回条数与去重;最后把任务状态外置,关键结论写成结构化字段,每轮只带状态不带全部历史。回答时补上取舍:摘要省 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²) 写法,并确认题目是否要求下标去重、结果是否按升序输出。