当前位置:首页>python>Python基础与后端工程 —— 全栈能力深度面试指南

Python基础与后端工程 —— 全栈能力深度面试指南

  • 2026-10-11 07:03:41
Python基础与后端工程 —— 全栈能力深度面试指南

1. Python中列表、元组的区别?深拷贝和浅拷贝的区别?

答:

列表 vs 元组

维度
列表(list)
元组(tuple)
可变性
可变,支持增删改
不可变,创建后不能修改
语法[1, 2, 3](1, 2, 3)
性能
较慢(需动态内存管理)
较快(固定内存,可被缓存)
哈希
不可哈希,不能作为dict的key
可哈希(元素也需可哈希),可以作为dict的key
使用场景
需要动态增删的集合
常量数据、函数多返回值、dict的key

深拷贝 vs 浅拷贝

维度
浅拷贝(Shallow Copy)
深拷贝(Deep Copy)
方式copy.copy()
、切片[:]、list()
copy.deepcopy()
行为
只复制外层对象,内层对象仍引用原对象
递归复制所有层级的对象
影响
修改内层元素会影响原对象
完全独立,互不影响
import copya = [[1, 2], [3, 4]]b = copy.copy(a)        # 浅拷贝:b[0] is a[0] → Truec = copy.deepcopy(a)    # 深拷贝:c[0] is a[0] → Falsea[0][0] = 99print(b)  # [[99, 2], [3, 4]]  ← 浅拷贝受影响print(c)  # [[1, 2], [3, 4]]   ← 深拷贝不受影响

延伸问题:

Q: Python中哪些操作会产生浅拷贝?A: copy.copy()、列表切片[:]、list()构造函数、dict.copy()、{k: v for k, v in d.items()}等。

Q: 元组真的完全不可变吗?A: 元组本身不可变(不能增删元素),但如果元组包含可变对象(如列表),该可变对象的内容可以修改:t = (1, [2, 3]),t[1].append(4) 是合法的。


2. 迭代器和生成器的区别?

答:

维度
迭代器(Iterator)
生成器(Generator)
定义
实现了__iter__()和__next__()的对象
使用yield关键字或生成器表达式的函数
创建方式
手动实现类或调用iter()
函数中使用yield或(x for x in range(n))
内存
需要自行管理状态
自动保存函数状态,惰性求值
代码量
较多(需实现类)
极少(一个函数即可)
# 迭代器classMyIter:def__init__(self, n):        self.n, self.i = n, 0def__iter__(self):return selfdef__next__(self):if self.i >= self.n: raise StopIteration        self.i += 1; return self.i# 生成器(等价实现)defmy_gen(n):for i in range(1, n+1):yield i

核心区别: 生成器是迭代器的"语法糖",用更简洁的代码实现相同功能,且自动支持惰性求值(按需生成数据,不一次性加载到内存)。

延伸问题:

Q: yield和return有什么区别?A: return返回值并结束函数;yield返回值但暂停函数,下次调用next()时从暂停处继续执行。

Q: 生成器只能遍历一次吗?为什么?A: 是的。生成器是惰性的,遍历时消费元素,遍历完后抛出StopIteration。如果需要重复遍历,需要重新创建生成器。


3. 有序数组插入新数的时间复杂度?如何判断链表有环?

答:

有序数组插入

  • 时间复杂度:O(n)
  • 原因:需要先用二分查找O(log n)找到插入位置,但插入时需要将该位置及之后的元素全部后移一位,最坏情况移动n个元素,所以总体是O(n)。

判断链表有环:快慢指针法(Floyd判圈算法)

defhas_cycle(head):    slow = fast = headwhile fast and fast.next:        slow = slow.next        fast = fast.next.nextif slow == fast:returnTruereturnFalse
  • 原理: 慢指针每次走1步,快指针每次走2步。如果有环,快指针一定会追上慢指针(在环内相遇);如果无环,快指针先到达None。
  • 时间复杂度:O(n),空间复杂度:O(1)

延伸问题:

Q: 如何找到环的入口节点?A: 快慢指针相遇后,将其中一个指针重置到head,两个指针都每次走1步,再次相遇的位置就是环的入口。数学证明:设头到入口距离a,入口到相遇点b,环长c,则2(a+b) = a+b+nc,得a = nc-b = (n-1)c + (c-b),即从head和相遇点同时走会在入口相遇。

Q: 还有其他方法判断链表有环吗?A: 哈希表法:遍历链表,将每个节点存入set,如果遇到已存在的节点说明有环。时间O(n),空间O(n)。


4. 算法题:两数之和、二分查找

答:

两数之和(Two Sum)

deftwo_sum(nums, target):    seen = {}for i, num in enumerate(nums):        complement = target - numif complement in seen:return [seen[complement], i]        seen[num] = ireturn []
  • 思路: 哈希表一次遍历,边存边查。时间O(n),空间O(n)。

二分查找(Binary Search)

defbinary_search(nums, target):    left, right = 0, len(nums) - 1while left <= right:        mid = left + (right - left) // 2if nums[mid] == target:return midelif nums[mid] < target:            left = mid + 1else:            right = mid - 1return-1
  • 思路: 每次将搜索区间缩小一半。时间O(log n),空间O(1)。
  • 注意:mid = left + (right - left) // 2 防止 (left + right) 整数溢出。

延伸问题:

Q: 两数之和如果有重复元素怎么处理?A: 返回所有符合条件的索引对。可以用defaultdict(list)存储每个值的所有索引。

Q: 二分查找的边界条件容易出错的地方?A: left <= right 还是 left < right 取决于区间定义(闭区间 vs 左闭右开)。循环不变量要一致:如果用闭区间[left, right],则left <= right;如果用左闭右开[left, right),则left < right。


5. 装饰器的作用是什么?

答: 装饰器(Decorator)是Python的语法糖,用于在不修改原函数代码的情况下,为函数/类添加额外功能。本质是一个高阶函数(接收函数作为参数,返回新函数)。

import timedeftimer(func):defwrapper(*args, **kwargs):        start = time.time()        result = func(*args, **kwargs)        print(f"{func.__name__} 耗时: {time.time()-start:.3f}s")return resultreturn wrapper@timerdefslow_function():    time.sleep(1)

常见用途:

  • 日志记录、性能计时
  • 权限校验、登录检查
  • 缓存(如@lru_cache)
  • 重试机制
  • 输入校验

延伸问题:

Q: 如何保留被装饰函数的元信息(如__name__)?A: 在wrapper函数上加@functools.wraps(func),它会将原函数的__name__、__doc__等属性复制到wrapper上。

Q: 装饰器可以带参数吗?怎么实现?A: 可以,需要三层嵌套函数:外层接收装饰器参数,中层接收被装饰函数,内层是实际执行逻辑。例如@retry(max_attempts=3)。


6. Python有哪些常用的库?

答: 按领域分类:

领域
常用库
数据处理
NumPy(数值计算)、Pandas(数据分析)、Polars(高性能DataFrame)
可视化
Matplotlib、Seaborn、Plotly
机器学习
Scikit-learn、XGBoost、LightGBM
深度学习
PyTorch、TensorFlow、Transformers(HuggingFace)
NLP
jieba(分词)、spaCy、NLTK
Web框架
Flask、FastAPI、Django
爬虫
Requests、Scrapy、BeautifulSoup、Selenium
数据库
SQLAlchemy、PyMySQL、Pymongo、pymilvus
异步
asyncio、aiohttp、Celery
工具
os、json、re、logging、argparse

延伸问题:

Q: NumPy的ndarray和Python list有什么区别?A: ndarray是同质连续内存数组,支持向量化运算(无需循环),底层C实现,速度比list快10-100倍;list是Python对象数组,元素类型可以不同,支持动态增删。


7. Flask和FastAPI的区别?有没有更深入的了解?

答:

维度
Flask
FastAPI
发布年份
2010
2018
性能
较慢(同步WSGI)
极快(异步ASGI,基于Starlette)
类型检查
无原生支持
基于Pydantic,自动数据校验
API文档
需手动集成Swagger
自动生成OpenAPI文档(/docs)
异步支持
2.0后支持,但非原生
原生async/await支持
依赖注入
需第三方库
原生Depends()机制
适合场景
简单Web应用、原型开发
高性能API服务、生产级微服务

FastAPI核心优势:

  1. 性能: 接近Node.js和Go的性能水平
  2. 自动文档: 访问/docs即可看到Swagger UI
  3. 类型安全: 请求参数自动校验,减少运行时错误
  4. 异步原生: 天然支持高并发场景
from fastapi import FastAPIfrom pydantic import BaseModelapp = FastAPI()classItem(BaseModel):    name: str    price: float@app.post("/items/")asyncdefcreate_item(item: Item):# 自动校验请求体return {"name": item.name, "total": item.price * 1.1}

延伸问题:

Q: FastAPI的依赖注入(Depends)是什么?有什么好处?A: Depends是FastAPI的依赖注入系统,可以将通用逻辑(如数据库连接、认证、参数解析)抽取为独立的依赖函数,由框架自动调用。好处:代码复用、解耦、便于测试。

Q: WSGI和ASGI有什么区别?A: WSGI(Web Server Gateway Interface)是同步标准,一次处理一个请求;ASGI(Asynchronous Server Gateway Interface)是异步标准,支持WebSocket、HTTP/2等,能并发处理多个请求。


8. 用Python代码怎么实现流式输出?

答:

# 方式一:SSE(Server-Sent Events)— 最常用from fastapi import FastAPIfrom fastapi.responses import StreamingResponseimport asyncioapp = FastAPI()asyncdefgenerate_stream():for chunk in ["Hello", " World", "!"]:yieldf"data: {chunk}\n\n"await asyncio.sleep(0.5)@app.get("/stream")asyncdefstream():return StreamingResponse(generate_stream(), media_type="text/event-stream")# 方式二:调用大模型的流式APIfrom openai import OpenAIclient = OpenAI()stream = client.chat.completions.create(    model="gpt-4",    messages=[{"role": "user", "content": "你好"}],    stream=True)for chunk in stream:if chunk.choices[0].delta.content:        print(chunk.choices[0].delta.content, end="", flush=True)

流式输出的核心原理: 服务端不等全部数据生成完再返回,而是每生成一部分就通过HTTP长连接推送一部分给客户端。客户端逐块接收并渲染。

延伸问题:

Q: 流式输出和普通HTTP响应有什么区别?A: 普通HTTP响应是"请求-等待-完整返回";流式输出是"请求-逐块返回",客户端无需等待全部数据生成,首字延迟(TTFT)更低,用户体验更好。


9. 流式输出怎么判断是否全部结束?

答:

# SSE协议中,通过特殊标记判断结束asyncdefgenerate():for chunk in data:yieldf"data: {chunk}\n\n"yield"data: [DONE]\n\n"# 结束标记# 客户端判断for chunk in stream:if chunk.strip() == "data: [DONE]":        print("流式输出结束")break# 处理正常数据...# OpenAI风格:检查 finish_reasonfor chunk in stream:if chunk.choices[0].finish_reason == "stop":        print("生成结束")break

常见判断方式:

  1. 特殊结束标记: 如[DONE]、[END]
  2. finish_reason字段: 模型返回的元数据中标记结束原因(stop/length)
  3. 连接关闭: 服务端关闭连接(HTTP连接断开)
  4. 内容校验: 检查返回内容是否为空或特定终止符

延伸问题:

Q: 流式输出中如果网络断开怎么办?A: 客户端检测到连接断开后,可以实现重连机制(携带上次的position参数请求续传),服务端需要支持从指定位置继续生成。也可以使用断点续传的SSE方案。


10. MySQL数据库如果有十万条数据,性能如何优化?

答:

1. 索引优化

-- 为常用查询字段创建索引CREATEINDEX idx_name ONusers(name);-- 复合索引(遵循最左前缀原则)CREATEINDEX idx_name_age ONusers(name, age);-- 覆盖索引:查询字段都在索引中,避免回表SELECTname, age FROMusersWHEREname = '张三';

2. 查询优化

  • 避免SELECT *,只查需要的字段
  • 避免在WHERE条件中对索引列使用函数(如WHERE YEAR(create_time) = 2024)
  • 用EXPLAIN分析执行计划,关注type、key、rows、Extra字段
  • 避免OR导致索引失效,改用UNION

3. 分页优化

-- 慢:OFFSET越大越慢SELECT * FROMusersLIMIT90000, 10;-- 快:基于游标的分页SELECT * FROMusersWHEREid > 90000LIMIT10;

4. 架构优化

  • 读写分离:主库写,从库读
  • 分库分表:按业务或时间维度拆分
  • 缓存层:热点数据放入Redis

延伸问题:

Q: MySQL索引的底层数据结构是什么?为什么用B+树而不是B树?A: InnoDB使用B+树。B+树的优势:1) 非叶子节点只存key不存data,单个节点能存更多key,树更矮,IO次数更少;2) 叶子节点用链表连接,范围查询高效;3) 所有数据都在叶子节点,查询效率稳定。


11. Redis存放哪些数据?

答: 在RAG/AI系统中,Redis常用于存放:

数据类型
示例
Redis数据结构
会话缓存
用户对话历史
String / List
热点查询缓存
高频Query的检索结果
String(JSON序列化)
分布式锁
防止并发写入冲突
String(SETNX)
限流计数器
API调用频率限制
String(INCR)
用户Session
登录状态、权限信息
Hash
任务队列
异步任务排队
List / Stream
排行榜
热门问题排名
Sorted Set
布隆过滤器
URL去重、缓存穿透防护
RedisBloom模块
import redisr = redis.Redis(host='localhost', port=6379, db=0)# 缘存查询结果(String)r.setex("query:你好", 3600, json.dumps({"answer": "你好啊"}))# 存储对话历史(List)r.rpush("chat:user123", "用户: 你好", "AI: 你好啊")r.ltrim("chat:user123", -20, -1)  # 只保留最近20条

延伸问题:

Q: Redis和Memcached有什么区别?A: Redis支持更丰富的数据结构(String/List/Hash/Set/ZSet)、支持持久化(RDB/AOF)、支持发布订阅、支持Lua脚本;Memcached只支持简单的key-value,多线程架构,在纯缓存场景下性能略优。


12. Redis是怎么进行持久化缓存的?

答: Redis提供两种持久化方式:

RDB(Redis Database Snapshot)

  • 原理: 在指定时间间隔内,将内存中的数据快照写入磁盘(.rdb文件)
  • 触发方式:SAVE(阻塞)/ BGSAVE(后台fork子进程)
  • 优点: 文件紧凑,适合备份和恢复
  • 缺点: 可能丢失最后一次快照后的数据

AOF(Append Only File)

  • 原理: 将每个写命令追加到日志文件(.aof)
  • 同步策略:always(每条命令)/ everysec(每秒)/ no(由OS决定)
  • 优点: 数据安全性高,最多丢失1秒数据
  • 缺点: 文件较大,恢复速度较慢

混合持久化(Redis 4.0+)

  • 原理: AOF重写时,前半部分用RDB格式,后半部分用AOF格式
  • 优点: 兼顾恢复速度和数据安全性
# redis.conf 配置save 900 1        # 900秒内至少1个key变化则触发RDBappendonly yes     # 开启AOFappendfsync everysec  # 每秒同步一次

延伸问题:

Q: Redis的内存淘汰策略有哪些?A: 8种策略:noeviction(不淘汰,写入报错)、allkeys-lru(所有key中淘汰最近最少使用)、volatile-lru(过期key中淘汰LRU)、allkeys-lfu(淘汰最不经常使用)、volatile-lfu、allkeys-random、volatile-random、volatile-ttl(淘汰TTL最短的)。生产环境常用allkeys-lru。


核心知识点分析

题号
核心知识点
考察维度
1
列表/元组差异、深浅拷贝
Python基础数据类型理解
2
迭代器/生成器、惰性求值
Python高级特性
3
时间复杂度、快慢指针
算法基础、链表操作
4
哈希查找、二分查找
经典算法编码能力
5
装饰器、高阶函数
Python函数式编程
6
Python生态库全景
技术广度
7
Flask vs FastAPI、WSGI/ASGI
Web框架选型能力
8
流式输出、SSE协议
实时通信工程能力
9
流式协议细节、结束判断
工程细节把控
10
MySQL索引优化、分页优化
数据库性能调优
11
Redis应用场景、数据结构选型
缓存设计能力
12
Redis持久化(RDB/AOF)
数据可靠性保障

知识图谱总结

本模块围绕Python基础与后端工程展开,涵盖四大核心主题:

  1. Python语言基础(1-5): 数据类型、深浅拷贝、迭代器/生成器、装饰器——考察对Python语言本质的理解深度。
  2. 算法与数据结构(3-4): 时间复杂度分析、快慢指针、哈希查找、二分查找——考察编码基本功。
  3. Web框架与API设计(7-9): Flask/FastAPI选型、流式输出实现、SSE协议——考察后端工程能力。
  4. 数据库与缓存(10-12): MySQL索引优化、Redis数据结构与持久化——考察数据层设计能力。

最新文章

随机文章