华为OD杭州 Python技术一面 - 八股文备考指南
字数
4308 字
阅读时间
20 分钟
基于
python.txt整理 + 高频面试题补充
第一部分:核心基础题(txt原文)
1. Python基础数据类型
| 类型 | 分类 | 可变/不可变 | 说明 |
|---|---|---|---|
| int, float, complex | 数值类型 | 不可变 | 赋值即创建新对象 |
| str | 字符串 | 不可变 | 拼接/替换生成新字符串 |
| tuple | 元组 | 不可变 | 创建后不能增删改 |
| list | 列表 | 可变 | 可以增删改查 |
| dict | 字典 | 可变 | key必须是不可变类型 |
| set, frozenset | 集合 | set可变, frozenset不可变 | 去重+集合运算 |
| bytes, bytearray | 字节 | bytes不可变, bytearray可变 | 二进制数据处理 |
| bool | 布尔 | 不可变 | 是int的子类,只有True/False |
| None | 空值 | 不可变 | 单例对象 |
记忆技巧:基本数据类型(数值、字符串、元组)都是不可变的;容器类型中list、dict、set是可变的。
2. 字典、列表、元组的区别
| 特性 | list (列表) | tuple (元组) | dict (字典) |
|---|---|---|---|
| 表示符号 | [] | () | {} |
| 可变性 | 可变 | 不可变 | 可变 |
| 存储方式 | 有序元素集合 | 有序不可变集合 | 键值对集合 |
| 访问方式 | 索引/切片 | 索引/切片 | key访问 |
| 查找效率 | O(n) 遍历 | O(n) 遍历 | O(1) 哈希 |
| 使用场景 | 存同类可变元素 | 存固定结构数据 | 存键值映射关系 |
元组的特殊用途:
- 作为函数返回多值的载体
- 作为字典的key(list不行)
- 记录固定结构的数据(如数据库记录)
3. 常用内置函数
字符串常用方法(至少6个)
python
s = " Hello, World "
# 1. len() - 长度
len(s) # 返回15
# 2. upper() / lower() - 大小写转换
s.upper() # " HELLO, WORLD "
s.lower() # " hello, world "
# 3. strip() - 去首尾空白
s.strip() # "Hello, World"
s.rstrip() # 去右侧
s.lstrip() # 去左侧
# 4. find() / rfind() - 查找子串
s.find("World") # 返回索引,找不到返回-1
s.rfind("o") # 从右侧找
# 5. index() / rindex() - 同find但找不到报错
s.index("World") # 返回索引
# s.index("xyz") # ValueError
# 6. replace() - 替换
s.replace("World", "Python") # " Hello, Python "
# 7. split() / join() - 分割/拼接
s.split(",") # [" Hello", " World "]
"-".join(["a","b","c"]) # "a-b-c"
# 8. startswith() / endswith() - 前缀/后缀判断
s.startswith(" Hello") # True
s.endswith("World ") # True
# 9. count() - 计数
s.count("l") # 3
# 10. format() / f-string - 格式化
"{} age {}".format("Tom", 20) # "Tom age 20"
name, age = "Tom", 20
f"{name} age {age}" # "Tom age 20"list常用方法(增删改查)
python
lst = [1, 2, 3]
# 增
lst.append(4) # 末尾追加 → [1,2,3,4]
lst.insert(0, 0) # 指定位置插入 → [0,1,2,3,4]
lst.extend([5,6]) # 扩展 → [0,1,2,3,4,5,6]
# 删
lst.remove(0) # 按值删除第一个匹配项 → [1,2,3,4,5,6]
lst.pop() # 弹出末尾元素,可指定索引
del lst[0] # 按索引删除
# 改
lst[0] = 100 # 直接索引赋值
# 查
lst.index(3) # 查找值的索引
lst.count(3) # 统计出现次数
3 in lst # 成员判断
# 排序
lst.sort() # 原地排序
sorted(lst) # 返回新排序列表
lst.reverse() # 反转4. 面向对象三大特性
| 特性 | 概念 | 示例 |
|---|---|---|
| 封装 | 将数据和方法包装在类中,隐藏内部实现,对外提供接口 | class中定义私有属性__attr |
| 继承 | 子类获取父类的属性和方法,实现代码复用 | class Dog(Animal) |
| 多态 | 不同类有相同的方法名但实现不同,调用时动态决定 | Animal.speak() 和 Dog.speak() 行为不同 |
重写 vs 重载
| 概念 | 定义 | Python支持情况 |
|---|---|---|
| 重写(Override) | 子类重新实现父类的方法,方法签名必须相同 | ✅ 支持,Python原生支持 |
| 重载(Overload) | 同一个方法名根据参数类型/数量不同有不同实现 | ❌ Python不原生支持,但可用默认参数/*args模拟 |
重写示例:
pythonclass Animal: def speak(self): return "Animal speaks" class Dog(Animal): def speak(self): # 重写父类方法 return "Dog barks"模拟重载:
pythondef add(a, b, c=0): return a + b + c add(1, 2) # 3 add(1, 2, 3) # 6
5. lambda函数(匿名函数)
概念
lambda是一个表达式,不是语句。函数的结果就是表达式的值。可以用在任何需要函数对象的地方。
示例
python
# 1. 计算两数平方和
f = lambda x, y: x**2 + y**2
f(3, 4) # 25
# 2. 筛选偶数(配合filter)
nums = [1, 2, 3, 4, 5, 6]
evens = list(filter(lambda x: x % 2 == 0, nums)) # [2, 4, 6]
# 3. 转换平方(配合map)
squares = list(map(lambda x: x**2, [1, 2, 3, 4, 5])) # [1, 4, 9, 16, 25]
# 4. 配合sorted的key参数
students = [("Alice", 90), ("Bob", 85), ("Charlie", 95)]
sorted(students, key=lambda x: x[1]) # 按分数排序6. 深拷贝 vs 浅拷贝
核心区别
| 类型 | 拷贝行为 | 嵌套可变类型变化 |
|---|---|---|
赋值 b = a | 不拷贝,两个变量指向同一对象 | 改a则b也变 |
浅拷贝 b = copy.copy(a) | 拷贝外层对象,内层引用共享 | 子变父也变 |
深拷贝 b = copy.deepcopy(a) | 完全独立的新对象(递归拷贝) | 子变父不变 |
示例
python
import copy
a = [[1, 2], [3, 4]]
# 赋值
b = a
a[0].append(99)
# b也变成[[1,2,99],[3,4]]
# 浅拷贝
c = copy.copy(a)
a[0].append(88)
# c的[0]也变成[1,2,99,88](内层引用共享)
# 但c.append([5,6]) 不影响a(外层是新对象)
# 深拷贝
d = copy.deepcopy(a)
a[0].append(77)
# d完全不受影响7. 装饰器
概念
装饰器是一种在不修改原函数代码的情况下,给函数增加额外功能的机制。本质上是闭包的应用。
为什么用装饰器?
- 代码复用:多个函数需要相同的日志、权限、计时等功能
- 无侵入性:不需要修改原函数的业务逻辑
- 关注点分离:把横切关注点(logging、caching等)从业务逻辑中分离
手写装饰器示例
python
def timer(func):
import time
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
print(f"耗时: {time.time() - start}s")
return result
return wrapper
@timer # 使用装饰器语法糖
def slow_func():
time.sleep(1)
return "done"
slow_func() # 自动打印耗时常见装饰器
| 装饰器 | 作用 |
|---|---|
@classmethod | 类方法,第一个参数是cls |
@staticmethod | 静态方法,不需要self/cls |
@property | 将方法变为属性访问 |
@pytest.fixture | 测试夹具,提供预定义数据 |
@pytest.mark.parametrize | 参数化测试用例 |
@langchain_core.tools.tool | LangChain工具装饰器(你的项目中用到了!) |
FastAPI的@app.get/@app.post | 路由装饰器 |
8. 列表推导式
基本语法
[表达式 for 变量 in 可迭代对象 if 条件]示例
python
# 1. 1-10的平方
squares = [i**2 for i in range(1, 11)]
# [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# 2. 1-10的偶数平方
even_squares = [i**2 for i in range(1, 11) if i % 2 == 0]
# [4, 16, 36, 64, 100]
# 3. 字符串处理
names = ["Alice", "Bob", "Charlie"]
upper_names = [name.upper() for name in names]
# 4. 二维列表展平
matrix = [[1, 2, 3], [4, 5, 6]]
flat = [x for row in matrix for x in row] # [1,2,3,4,5,6]
# 5. 条件嵌套(用else)
labels = ["even" if i % 2 == 0 else "odd" for i in range(1, 6)]
# ['odd', 'even', 'odd', 'even', 'odd']9. 字典推导式
基本语法
{key: value for 变量1, 变量2 in 可迭代对象 if 条件}示例
python
# 1. 从两个列表生成字典(用zip配对)
keys = ["name", "age", "city"]
values = ["Tom", 20, "Hangzhou"]
d = {k: v for k, v in zip(keys, values)}
# {"name": "Tom", "age": 20, "city": "Hangzhou"}
# 2. 给字典值+1
dd = {"a": 1, "b": 2, "c": 3}
dd_new = {k: v + 1 for k, v in dd.items()}
# {"a": 2, "b": 3, "c": 4}
# 3. 统计字符串中每个字符出现次数
text = "hello world"
char_count = {c: text.count(c) for c in set(text)}
# 4. 过滤掉值为空的字典
data = {"name": "Tom", "email": None, "phone": "123"}
clean = {k: v for k, v in data.items() if v is not None}
# {"name": "Tom", "phone": "123"}10. 三元运算符
基本语法
值1 if 条件 else 值2示例
python
# 1. 两数取较大值
a, b = 10, 20
max_val = a if a > b else b # 20
# 2. 成绩评定(嵌套三元)
score = 85
grade = "优秀" if score >= 90 else (
"良好" if score >= 80 else (
"及格" if score >= 60 else "不及格"
)
)
# "良好"
# 3. 列表过滤
nums = [1, 2, 3, 4, 5]
result = ["big" if n > 3 else "small" for n in nums]
# ['small', 'small', 'small', 'big', 'big']11. Python常用库
标准库
| 库 | 用途 | 示例 |
|---|---|---|
os / sys | 操作系统/系统参数 | os.path.join(), sys.argv |
json | JSON序列化/反序列化 | json.dumps(), json.loads() |
re | 正则表达式 | re.match(), re.findall() |
datetime | 日期时间处理 | datetime.now(), timedelta |
collections | 高级数据结构 | Counter, defaultdict, OrderedDict |
itertools | 迭代器工具 | chain(), product(), combinations() |
copy | 深浅拷贝 | copy(), deepcopy() |
logging | 日志记录 | basicConfig(), getLogger() |
threading / multiprocessing | 多线程/多进程 | Thread, Process |
asyncio | 异步IO | asyncio.run(), await |
常用第三方库
| 库 | 用途 |
|---|---|
| pandas | 数据分析、处理Excel/CSV |
| numpy | 数值计算、数组运算 |
| requests | HTTP请求 |
| beautifulsoup4 / lxml | HTML/XML解析 |
| selenium | 浏览器自动化 |
| fastapi | 现代Web框架 |
| flask | 轻量级Web框架 |
| django | 全栈Web框架 |
| pydantic | 数据校验/类型注解 |
| sqlalchemy | ORM框架 |
| langchain | LLM应用开发框架 |
12. 正则表达式
常用方法对比
| 方法 | 作用 | 返回值 | 搜索范围 |
|---|---|---|---|
re.match() | 从字符串开头匹配 | Match对象或None | 只匹配开头 |
re.search() | 扫描整个字符串找第一个匹配 | Match对象或None | 全字符串,找第一个 |
re.findall() | 找所有匹配,返回列表 | 列表 | 全字符串,所有匹配 |
re.sub() | 替换匹配内容 | 新字符串 | 全字符串,默认替换所有 |
示例
python
import re
text = "Python3 is great. Python2 is old. python3.10"
# match - 只从开头找
re.match(r"Python", text) # Match对象
re.match(r"Python", " " + text) # None(不是开头)
# search - 找第一个
re.search(r"Python", text) # Match对象(第一个Python)
# findall - 找所有
re.findall(r"[Pp]ython\d*", text) # ["Python3", "Python2", "python3"]
# sub - 替换
re.sub(r"\d+", "N", text) # "PythonN is great. PythonN is old. pythonN.N"
# 常用正则模式
# 邮箱: r"[\w.-]+@[\w.-]+\.\w+"
# 手机号: r"1[3-9]\d{9}"
# URL: r"https?://[\w./-]+"13. 迭代器、可迭代对象、生成器
核心概念
| 概念 | 定义 | 特点 |
|---|---|---|
| 可迭代对象(Iterable) | 能被for循环遍历的对象 | 实现了__iter__()或__getitem__(),如list、dict、str |
| 迭代器(Iterator) | 实现了__iter__()和__next__()的对象 | __iter__()返回自身,__next__()返回下一个值或抛StopIteration |
| 生成器(Generator) | 一种特殊的迭代器,用yield关键字 | 惰性生成,节省内存,每次只产生一个值 |
关系图
Iterable → (调用__iter__) → Iterator → (调用__next__) → 逐个取值示例
python
# 可迭代对象
my_list = [1, 2, 3]
for x in my_list: ... # for循环自动调用__iter__获取迭代器
# 迭代器
my_iter = iter(my_list) # 调用__iter__
next(my_iter) # 1
next(my_iter) # 2
next(my_iter) # 3
# next(my_iter) → StopIteration
# 生成器
def my_gen(n):
for i in range(n):
yield i ** 2
g = my_gen(5)
next(g) # 0
next(g) # 1
# 惰性计算,省内存
# 列表推导式 vs 生成器表达式
lst = [i**2 for i in range(10000)] # 一次性全部生成,占内存
gen = (i**2 for i in range(10000)) # 惰性生成,省内存14. 冒泡排序
代码实现
python
def bubble_sort(arr):
n = len(arr)
# 外层循环:控制排序轮数
for i in range(n - 1):
swapped = False
# 内层循环:两两比较并交换
for j in range(n - 1 - i):
if arr[j] > arr[j + 1]:
arr[j], arr[j + 1] = arr[j + 1], arr[j]
swapped = True
# 优化:如果本轮没有发生交换,说明已经有序
if not swapped:
break
return arr
# 测试
print(bubble_sort([64, 34, 25, 12, 22, 11, 90]))
# [11, 12, 22, 25, 34, 64, 90]复杂度分析
- 时间复杂度:O(n²)(最坏/平均),O(n)(最好,已有序时)
- 空间复杂度:O(1)(原地排序)
- 稳定性:稳定(相等元素相对位置不变)
第二部分:高频补充题
15. Python的内存管理机制
引用计数
- 每个对象维护一个引用计数
- 增加引用:
a = obj,b = obj,list.append(obj) - 减少引用:
del a, 函数返回,容器删除 - 优点:实时回收,无需等待
- 缺点:无法处理循环引用(两个对象互相引用)
标记-清除(Mark-Sweep)
- 从根对象出发,遍历所有引用
- 不可达的对象标记为垃圾
- 清理被标记的对象,释放内存
- 解决了循环引用问题
分代回收
- 分为三代:0代(新创建)、1代(经历过回收)、2代(长期存活)
- 回收频率:0代最频繁,1代较少,2代最少
- 依据:绝大多数对象都是朝生夕灭的
16. Python的GIL(全局解释器锁)
概念
GIL是一把互斥锁,确保同一时刻只有一个线程在执行Python字节码。
影响
- 多线程在CPU密集型任务中无法利用多核
- 多线程在IO密集型任务中有用(因为IO操作时会释放GIL)
解决方案
- 多进程:
multiprocessing,每个进程有独立的GIL - 协程:
asyncio,单线程实现高并发 - C扩展:在GIL外执行计算密集型操作
总结
| 方案 | CPU密集 | IO密集 |
|---|---|---|
| 多线程 | ❌ 受GIL限制 | ✅ 有效 |
| 多进程 | ✅ 利用多核 | ✅ 有效 |
| 协程 | ❌ 单线程 | ✅ 最高效 |
17. 深拷贝和浅拷贝的注意点
不可变对象的拷贝
- 对于int、str、tuple等不可变对象,浅拷贝和赋值效果类似
- 因为不可变对象本身就不能修改
python
a = 10
b = a # 赋值
c = copy.copy(a) # 浅拷贝
d = copy.deepcopy(a) # 深拷贝
# 三者指向同一个int对象,因为int不可变自定义对象的拷贝
python
class Node:
def __init__(self, val):
self.val = val
self.children = []
node1 = Node(1)
node1.children.append(Node(2))
# 浅拷贝
node2 = copy.copy(node1)
node2.val = 100 # 只影响node2
node2.children.append(Node(3)) # node1的children也会变!
# 深拷贝
node3 = copy.deepcopy(node1)
node3.children.append(Node(4)) # node1完全不受影响18. 闭包
概念
闭包是引用了外部函数变量的内部函数。即使外部函数已经返回,内部函数仍然可以访问外部变量。
示例
python
def make_counter():
count = 0
def counter():
nonlocal count # 声明使用外部变量
count += 1
return count
return counter
c = make_counter()
c() # 1
c() # 2
c() # 3用途
- 实现装饰器
- 实现工厂函数
- 模拟私有变量
19. 异常处理
基本结构
python
try:
# 可能出错的代码
result = risky_operation()
except ValueError as e:
# 捕获特定异常
print(f"值错误: {e}")
except (TypeError, KeyError) as e:
# 捕获多种异常
print(f"类型/键错误: {e}")
except Exception as e:
# 捕获所有异常(兜底)
print(f"未知错误: {e}")
else:
# 没有异常时执行
print("操作成功")
finally:
# 无论如何都会执行(常用于资源清理)
cleanup()自定义异常
python
class ValidationError(Exception):
def __init__(self, message, field):
self.message = message
self.field = field
super().__init__(message)
raise ValidationError("姓名不能为空", "name")20. with语句和上下文管理器
概念
with语句保证资源的正确获取和释放。
示例
python
# 文件操作
with open("data.txt", "r") as f:
content = f.read()
# 自动关闭文件
# 数据库连接
with db_connection as conn:
conn.execute(query)
# 自动提交/回滚
# 自定义上下文管理器
class DatabaseConnection:
def __enter__(self):
self.conn = create_connection()
return self.conn
def __exit__(self, exc_type, exc_val, exc_tb):
self.conn.close()
if exc_type:
print(f"发生异常: {exc_val}")
return False附录:面试高频场景题速答
Q: list和tuple的区别?实际使用场景?
tuple不可变,安全且可哈希(可作为dict的key)。适合存固定结构数据,如坐标(x,y)、配置项。list适合存可变集合。
Q: 装饰器的实现原理?
闭包 + 函数作为参数。装饰器本质是一个接受函数为参数的函数,返回一个新函数。
@decorator是语法糖,等价于func = decorator(func)。
Q: 生成器的优势?
惰性求值,节省内存。适合处理大数据集(逐行读取、无限序列)。用
yield关键字实现。
Q: 深拷贝一定要用吗?
不一定。只有当需要完全独立的副本时才用。如果只是需要一个新的引用容器,但内部元素共享,浅拷贝即可。
Q: lambda和def的区别?
lambda只能包含一个表达式,def可以包含多个语句。lambda适合写简单的一次性函数,def适合写复杂的可复用函数。