最近为了准备面试,我希望能够系统学习或复习一下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 == ⭐⭐⭐⭐⭐ ⭐⭐
深拷贝/浅拷贝 ⭐⭐⭐⭐⭐ ⭐⭐⭐
列表推导式 ⭐⭐⭐⭐⭐ ⭐⭐
字典底层实现 ⭐⭐⭐⭐ ⭐⭐⭐
小整数池/字符串驻留 ⭐⭐⭐ ⭐⭐⭐
可变默认参数陷阱 ⭐⭐⭐⭐⭐ ⭐⭐
海象运算符 ⭐⭐ ⭐⭐
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐