Python面试手册AI版——Part1
Python面试手册AI版,Part1——Python基础部分
·
最近为了准备面试,我希望能够系统学习或复习一下Python有关的知识,于是基于比较合理的prompt向AI问了一份比较详细的Python面试手册,觉得还不错,适合有Python基础的同学学习一下,所以这里也给大家分享出来,本篇文章是第一部分,大家一起学习~ 一起进步~ 一起涨薪~
🐍 Python 面试知识点手册
📚 目录总览
| 部分 | 主题 | 重要程度 |
|---|---|---|
| Part 1 | Python 基础 & 数据类型 | ⭐⭐⭐⭐⭐ |
| Part 2 | 函数 & 闭包 & 装饰器 | ⭐⭐⭐⭐⭐ |
| Part 3 | 面向对象 & 魔术方法 | ⭐⭐⭐⭐⭐ |
| Part 4 | 并发编程 (多线程/多进程/协程) | ⭐⭐⭐⭐⭐ |
| Part 5 | 内存管理 & GC & 性能优化 | ⭐⭐⭐⭐ |
| Part 6 | 常用标准库 & 第三方库 | ⭐⭐⭐⭐ |
| Part 7 | Web 框架 & 数据库 & 缓存 | ⭐⭐⭐⭐⭐ |
| Part 8 | 设计模式 & 系统设计 & 软技能 | ⭐⭐⭐⭐ |
Part 1: Python 基础 & 数据类型
一、Python 语言特性
1.1 Python 是什么类型的语言?
Python 是一门 动态类型、强类型、解释型 的高级编程语言。
详细解释:
| 特性 | 说明 | 示例 |
|---|---|---|
| 动态类型 | 变量类型在运行时确定,无需声明 | x = 1; x = "str" 合法 |
| 强类型 | 不同类型不会隐式转换 | "1" + 1 报错(不像 JS 会变成 "11") |
| 解释型 | 代码由解释器逐行执行,非编译为机器码 | 运行慢但开发快 |
面试追问:Python 是编译型还是解释型?
# 实际上 Python 有一个"编译"步骤,但不是编译成机器码
# 源码 (. py) → 字节码 (.pyc) → CPython 虚拟机解释执行
import py_compile
py_compile.compile('script.py') # 生成 __pycache__/script.cpython-311.pyc
1.2 Python 的解释器有哪些?
| 解释器 | 说明 | 使用场景 |
|---|---|---|
| CPython | 官方默认,C 语言实现 | 99% 的场景 |
| PyPy | JIT 编译,性能提升 2-10 倍 | CPU 密集型(不依赖 C 扩展时) |
| Jython | 运行在 JVM 上 | 需要与 Java 集成 |
| IronPython | 运行在 .NET 上 | 需要与 C# 集成 |
| MicroPython | 嵌入式设备 | IoT、单片机 |
二、数据类型详解(重点!)
2.1 Python 数据类型分类
# ============ 按可变性分类 ============
# 不可变类型 (Immutable) - 哈希值固定,可作为 dict 的 key
immutable_types = (
int, # 整数
float, # 浮点数
str, # 字符串
tuple, # 元组
frozenset, # 冻结集合
bytes, # 字节串
bool, # 布尔值 (int 的子类)
None.__class__, # NoneType
)
# 可变类型 (Mutable) - 不可哈希,不能作为 dict 的 key
mutable_types = (
list, # 列表
dict, # 字典
set, # 集合
bytearray, # 可变字节数组
)
# 验证:不可变类型可以作为 dict 的 key
d = {
1: "int",
"a": "str",
(1, 2): "tuple",
frozenset([1, 2]): "frozenset",
}
# 可变类型不行
# d = {[1, 2]: "list"} # TypeError: unhashable type: 'list'
2.2 整数 (int) 的底层实现
面试高频问题:Python 的整数有上限吗?
# Python 3 的 int 是任意精度的!没有溢出问题
big_num = 10 ** 1000 # 1001 位数字,完全没问题
print(len(str(big_num))) # 1001
# 底层原理:int 是变长对象
import sys
print(sys.getsizeof(0)) # 24 bytes (基础开销)
print(sys.getsizeof(1)) # 28 bytes
print(sys.getsizeof(10**100)) # 72 bytes (数字越大占用越多)
小整数池 (Small Integer Caching)
# Python 会预先缓存 [-5, 256] 范围内的整数
a = 256
b = 256
print(a is b) # True (同一个对象)
a = 257
b = 257
print(a is b) # False (不同对象,但值相等)
# 注意:在交互式环境和脚本中表现可能不同(编译器优化)
2.3 字符串 (str) 深度解析
字符串的不可变性
s = "hello"
# s[0] = "H" # TypeError: 'str' object does not support item assignment
# 每次"修改"都会创建新对象
s1 = "hello"
s2 = s1.upper()
print(id(s1), id(s2)) # 不同的内存地址
字符串驻留 (String Interning)
# Python 会自动驻留一些字符串,使它们共享内存
# 情况1:短字符串、标识符风格的字符串
a = "hello"
b = "hello"
print(a is b) # True (驻留)
# 情况2:带空格或特殊字符的不会自动驻留
a = "hello world"
b = "hello world"
print(a is b) # False(可能为 True,取决于编译器优化)
# 手动驻留
import sys
a = sys.intern("hello world!")
b = sys. intern("hello world!")
print(a is b) # True (强制驻留)
字符串常用操作(必须熟练)
s = " Hello, World! "
# ============ 常用方法 ============
s.strip() # "Hello, World!" (去除两端空白)
s.lstrip() # "Hello, World! "
s.rstrip() # " Hello, World!"
s.lower() # " hello, world! "
s. upper() # " HELLO, WORLD! "
s. title() # " Hello, World! "
s. capitalize() # " hello, world! "
s.strip().split(",") # ["Hello", " World!"]
",".join(["a", "b"]) # "a,b"
s.strip().replace("World", "Python") # "Hello, Python!"
s.strip().startswith("Hello") # True
s. strip().endswith("!") # True
s. find("World") # 9 (返回索引,找不到返回 -1)
s.index("World") # 9 (找不到抛出 ValueError)
s.count("l") # 3
# ============ 格式化 (重要!) ============
name, age = "Alice", 30
# 方式1:% 格式化(老式)
"Name: %s, Age: %d" % (name, age)
# 方式2:str.format()
"Name: {}, Age: {}".format(name, age)
"Name: {name}, Age: {age}".format(name=name, age=age)
# 方式3:f-string (Python 3.6+,推荐!)
f"Name: {name}, Age: {age}"
f"Next year: {age + 1}" # 支持表达式
f"{name: >10}" # 右对齐,宽度10
f"{3. 14159:.2f}" # 保留2位小数: "3.14"
# ============ 编码 ============
s = "你好"
b = s.encode("utf-8") # b'\xe4\xbd\xa0\xe5\xa5\xbd' (bytes)
s2 = b.decode("utf-8") # "你好"
2.4 列表 (list) 深度解析
列表的底层实现
# list 底层是动态数组(不是链表!)
# 特点:随机访问 O(1),尾部增删 O(1),中间增删 O(n)
import sys
lst = []
for i in range(10):
print(f"len={len(lst)}, size={sys.getsizeof(lst)} bytes")
lst.append(i)
# 输出(注意 size 变化):
# len=0, size=56 bytes
# len=1, size=88 bytes (预分配空间)
# len=2, size=88 bytes
# ...
# len=4, size=88 bytes
# len=5, size=120 bytes (扩容!)
时间复杂度对照表
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
lst[i] |
O(1) | 索引访问 |
lst.append(x) |
O(1) | 尾部追加(均摊) |
lst.pop() |
O(1) | 尾部弹出 |
lst.pop(0) |
O(n) | 头部弹出(需要移动元素) |
lst.insert(0, x) |
O(n) | 头部插入 |
x in lst |
O(n) | 线性搜索 |
lst.sort() |
O(n log n) | Timsort 算法 |
列表常用操作
# ============ 基础操作 ============
lst = [1, 2, 3, 4, 5]
lst.append(6) # [1, 2, 3, 4, 5, 6]
lst.extend([7, 8]) # [1, 2, 3, 4, 5, 6, 7, 8]
lst.insert(0, 0) # [0, 1, 2, 3, 4, 5, 6, 7, 8]
lst.pop() # 返回 8,lst = [0, 1, 2, 3, 4, 5, 6, 7]
lst.pop(0) # 返回 0,lst = [1, 2, 3, 4, 5, 6, 7]
lst.remove(3) # 删除第一个值为 3 的元素
lst.index(5) # 返回 3 (值为 5 的索引)
lst.count(5) # 返回 1 (值为 5 的个数)
lst.reverse() # 原地反转
lst.sort() # 原地排序
lst.sort(reverse=True) # 降序
lst.sort(key=lambda x: -x) # 自定义排序
# ============ 切片 (非常重要!) ============
lst = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
lst[2:5] # [2, 3, 4] (左闭右开)
lst[:3] # [0, 1, 2]
lst[7:] # [7, 8, 9]
lst[-3:] # [7, 8, 9] (最后3个)
lst[:-3] # [0, 1, 2, 3, 4, 5, 6] (除了最后3个)
lst[::2] # [0, 2, 4, 6, 8] (步长为2)
lst[: :-1] # [9, 8, 7, 6, 5, 4, 3, 2, 1, 0] (反转)
lst[1:8:2] # [1, 3, 5, 7] (从1到8,步长2)
# 切片赋值
lst[2:5] = [20, 30] # [0, 1, 20, 30, 5, 6, 7, 8, 9] (长度可以不同)
# ============ 列表推导式 (必须掌握!) ============
# 基础语法
squares = [x ** 2 for x in range(10)] # [0, 1, 4, 9, ...]
# 带条件
evens = [x for x in range(10) if x % 2 == 0] # [0, 2, 4, 6, 8]
# 嵌套
matrix = [[i * j for j in range(3)] for i in range(3)]
# [[0, 0, 0], [0, 1, 2], [0, 2, 4]]
# 多重循环
pairs = [(x, y) for x in range(3) for y in range(3) if x != y]
# [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
# ============ 浅拷贝 vs 深拷贝 (高频考点!) ============
import copy
# 原始列表
original = [[1, 2], [3, 4]]
# 浅拷贝 (只拷贝第一层)
shallow = original. copy() # 方式1
shallow = list(original) # 方式2
shallow = original[:] # 方式3
shallow = copy.copy(original) # 方式4
original[0][0] = 100
print(shallow[0][0]) # 100 !嵌套对象被修改了
# 深拷贝 (递归拷贝所有层)
original = [[1, 2], [3, 4]]
deep = copy.deepcopy(original)
original[0][0] = 100
print(deep[0][0]) # 1 ✅ 完全独立
2.5 字典 (dict) 深度解析
字典的底层实现
"""
Python 3.7+ 字典是有序的(保持插入顺序)
底层实现:哈希表 (Hash Table)
插入过程:
1. 计算 key 的哈希值: hash(key)
2. 通过哈希值定位桶位置: index = hash(key) % table_size
3. 处理哈希冲突 (开放寻址法)
4. 存储 key-value 对
时间复杂度:
- 查找/插入/删除: 平均 O(1),最坏 O(n)(极端哈希冲突)
"""
# 验证字典有序性 (Python 3.7+)
d = {"c": 3, "a": 1, "b": 2}
print(list(d.keys())) # ['c', 'a', 'b'] (保持插入顺序)
字典常用操作
# ============ 基础操作 ============
d = {"name": "Alice", "age": 30}
# 访问
d["name"] # "Alice"
d. get("name") # "Alice"
d.get("gender") # None (不存在时返回 None)
d.get("gender", "unknown") # "unknown" (指定默认值)
# 修改/新增
d["age"] = 31
d["gender"] = "female"
# 删除
del d["gender"]
d.pop("age") # 返回 30,并删除
d.pop("xxx", None) # 不存在时返回默认值,不报错
d.popitem() # 弹出最后一个 (Python 3.7+)
# 遍历
for key in d:
print(key, d[key])
for key, value in d.items():
print(key, value)
for key in d.keys():
print(key)
for value in d.values():
print(value)
# ============ 常用方法 ============
d = {"a": 1, "b": 2}
d.update({"c": 3, "d": 4}) # 批量更新
d.setdefault("e", 5) # 如果 key 不存在则设置,返回最终值
# 合并字典 (Python 3.9+)
d1 = {"a": 1}
d2 = {"b": 2}
d3 = d1 | d2 # {"a": 1, "b": 2}
d1 |= d2 # d1 = {"a": 1, "b": 2}
# ============ 字典推导式 ============
# 基础
squares = {x: x ** 2 for x in range(5)} # {0: 0, 1: 1, 2: 4, ... }
# 反转 key-value
d = {"a": 1, "b": 2}
reversed_d = {v: k for k, v in d.items()} # {1: "a", 2: "b"}
# 带条件
d = {x: x ** 2 for x in range(10) if x % 2 == 0}
# ============ defaultdict (collections 模块) ============
from collections import defaultdict
# 普通 dict 访问不存在的 key 会报错
d = {}
# d["key"] += 1 # KeyError
# defaultdict 自动初始化
d = defaultdict(int) # 默认值为 0
d["key"] += 1 # 正常工作
d = defaultdict(list) # 默认值为 []
d["key"].append(1)
d = defaultdict(lambda: "default")
print(d["any"]) # "default"
# ============ Counter (计数器) ============
from collections import Counter
# 统计元素出现次数
c = Counter([1, 2, 2, 3, 3, 3])
print(c) # Counter({3: 3, 2: 2, 1: 1})
print(c. most_common(2)) # [(3, 3), (2, 2)] (前2个最常见)
# 统计字符
c = Counter("hello world")
print(c) # Counter({'l': 3, 'o': 2, ... })
# ============ OrderedDict (3.7 前保持顺序) ============
from collections import OrderedDict
# Python 3.7+ 普通 dict 已有序,但 OrderedDict 有额外功能
od = OrderedDict()
od["a"] = 1
od["b"] = 2
od. move_to_end("a") # 移到末尾
od. move_to_end("b", last=False) # 移到开头
2.6 集合 (set) 与 frozenset
# set 是无序、不重复的集合,底层也是哈希表
# ============ 创建 ============
s = {1, 2, 3}
s = set([1, 2, 2, 3]) # {1, 2, 3} (自动去重)
s = set() # 空集合 (不是 {},那是空字典!)
# ============ 常用操作 ============
s = {1, 2, 3}
s.add(4) # {1, 2, 3, 4}
s.remove(4) # 删除,不存在则报错
s. discard(4) # 删除,不存在不报错
s. pop() # 随机弹出一个
s.clear() # 清空
# ============ 集合运算 (重要!) ============
a = {1, 2, 3, 4}
b = {3, 4, 5, 6}
# 并集
a | b # {1, 2, 3, 4, 5, 6}
a.union(b) # 同上
# 交集
a & b # {3, 4}
a.intersection(b) # 同上
# 差集
a - b # {1, 2} (在 a 中但不在 b 中)
a.difference(b) # 同上
# 对称差集 (在 a 或 b 中,但不同时在)
a ^ b # {1, 2, 5, 6}
a.symmetric_difference(b)
# 判断
{1, 2}. issubset({1, 2, 3}) # True (子集)
{1, 2, 3}.issuperset({1, 2}) # True (超集)
{1, 2}.isdisjoint({3, 4}) # True (无交集)
# ============ frozenset (不可变集合) ============
fs = frozenset([1, 2, 3])
# fs.add(4) # 报错,不可修改
# 可以作为 dict 的 key
d = {fs: "value"}
2.7 元组 (tuple)
# tuple 是不可变的列表
# ============ 创建 ============
t = (1, 2, 3)
t = 1, 2, 3 # 括号可省略
t = tuple([1, 2, 3])
t = (1,) # 单元素元组,必须有逗号!
# t = (1) # 这是 int,不是 tuple
# ============ 为什么需要 tuple? ============
# 1. 作为 dict 的 key
d = {(1, 2): "point"}
# 2. 函数返回多个值
def get_point():
return 1, 2 # 实际返回 tuple
x, y = get_point() # 解包
# 3. 作为不可变的数据容器(防止意外修改)
CONSTANTS = (3.14, 2.718, 1.414)
# 4. 性能略好于 list
import sys
print(sys.getsizeof((1, 2, 3))) # 64
print(sys.getsizeof([1, 2, 3])) # 88
# ============ 命名元组 (推荐!) ============
from collections import namedtuple
from typing import NamedTuple
# 方式1:collections.namedtuple
Point = namedtuple("Point", ["x", "y"])
p = Point(1, 2)
print(p.x, p.y) # 1 2
print(p[0], p[1]) # 1 2 (也支持索引)
# 方式2:typing.NamedTuple (推荐,支持类型注解)
class Point(NamedTuple):
x: int
y: int
z: int = 0 # 可以有默认值
p = Point(1, 2)
print(p. x, p.y, p.z) # 1 2 0
三、运算符与表达式
3.1 is vs == 的区别 (高频考点!)
"""
== : 值比较 (调用 __eq__ 方法)
is : 身份比较 (比较内存地址,等价于 id(a) == id(b))
"""
# 示例1:小整数池
a = 256
b = 256
print(a == b) # True
print(a is b) # True (小整数池)
a = 257
b = 257
print(a == b) # True
print(a is b) # False (不在小整数池)
# 示例2:字符串驻留
a = "hello"
b = "hello"
print(a is b) # True (驻留)
a = "hello world"
b = "hello world"
print(a is b) # 可能 True 或 False (取决于编译器)
# 示例3:可变对象
a = [1, 2, 3]
b = [1, 2, 3]
print(a == b) # True
print(a is b) # False (不同对象)
b = a
print(a is b) # True (同一个对象)
# ============ 最佳实践 ============
# 判断是否为 None 必须用 is
if x is None:
pass
# 判断类型用 isinstance,不要用 is
if isinstance(x, list): # ✅
pass
# if type(x) is list: # ❌ 不推荐,无法处理继承
3.2 逻辑运算的短路特性
"""
and : 第一个 False 就返回,否则返回最后一个值
or : 第一个 True 就返回,否则返回最后一个值
"""
# and 短路
print(0 and 1) # 0 (第一个为 False,直接返回)
print(1 and 2) # 2 (都为 True,返回最后一个)
print(1 and 2 and 3) # 3
# or 短路
print(0 or 1) # 1 (第一个为 False,继续判断)
print(1 or 2) # 1 (第一个为 True,直接返回)
print(0 or "" or []) # [] (都为 False,返回最后一个)
# 实际应用:设置默认值
name = input_name or "Anonymous"
# 实际应用:条件执行
debug and print("Debug info") # 只有 debug 为 True 才打印
3.3 海象运算符 := (Python 3.8+)
# 在表达式中赋值,减少重复计算
# ============ 示例1:while 循环 ============
# 之前
while True:
line = input()
if line == "quit":
break
process(line)
# 使用海象运算符
while (line := input()) != "quit":
process(line)
# ============ 示例2:if 条件 ============
# 之前
match = pattern. search(text)
if match:
print(match.group())
# 使用海象运算符
if (match := pattern.search(text)):
print(match.group())
# ============ 示例3:列表推导式 ============
# 避免重复计算
results = [y for x in data if (y := expensive_func(x)) > 0]
四、常见面试题
4.1 交换两个变量的值
# Python 特有的优雅写法
a, b = b, a
# 底层原理:元组解包
# 等价于:
# temp = (b, a)
# a = temp[0]
# b = temp[1]
4.2 判断一个对象是什么类型
x = [1, 2, 3]
# 方式1:type() - 不考虑继承
print(type(x)) # <class 'list'>
print(type(x) == list) # True
# 方式2:isinstance() - 考虑继承 (推荐)
print(isinstance(x, list)) # True
print(isinstance(x, (list, tuple))) # True (多类型判断)
# 方式3:检查是否有某个属性/方法(鸭子类型)
print(hasattr(x, '__iter__')) # True (可迭代)
4.3 列表去重并保持顺序
# 方式1:使用 dict. fromkeys() (推荐)
lst = [3, 1, 2, 1, 3, 2, 4]
result = list(dict.fromkeys(lst)) # [3, 1, 2, 4]
# 方式2:使用 set + 保持顺序
seen = set()
result = [x for x in lst if not (x in seen or seen.add(x))]
# 方式3:Python 3.7+ 直接用 dict
result = list({x: None for x in lst}. keys())
# 如果不需要保持顺序
result = list(set(lst)) # 顺序不确定
4.4 合并两个字典
d1 = {"a": 1, "b": 2}
d2 = {"b": 3, "c": 4}
# 方式1:| 运算符 (Python 3.9+,推荐)
result = d1 | d2 # {"a": 1, "b": 3, "c": 4}
# 方式2:** 解包
result = {**d1, **d2}
# 方式3:update() (会修改原字典)
d1.update(d2)
# 方式4:ChainMap (不真正合并,创建视图)
from collections import ChainMap
combined = ChainMap(d2, d1) # d2 优先
4.5 可变默认参数陷阱 (必考!)
# ❌ 错误示例
def append_to(element, lst=[]):
lst.append(element)
return lst
print(append_to(1)) # [1]
print(append_to(2)) # [1, 2] ← 期望 [2],但得到 [1, 2]!
# 原因:默认参数只在函数定义时创建一次
# ✅ 正确做法
def append_to(element, lst=None):
if lst is None:
lst = []
lst.append(element)
return lst
📝 Part 1 总结
| 知识点 | 面试频率 | 难度 |
|---|---|---|
| 可变/不可变类型 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| is vs == | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| 深拷贝/浅拷贝 | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
| 列表推导式 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| 字典底层实现 | ⭐⭐⭐⭐ | ⭐⭐⭐ |
| 小整数池/字符串驻留 | ⭐⭐⭐ | ⭐⭐⭐ |
| 可变默认参数陷阱 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| 海象运算符 | ⭐⭐ | ⭐⭐ |
更多推荐


所有评论(0)