Python 数据类型详解
1️⃣ 数值类型(Number)
| 类型 | 核心特性 | 可变性 | 常用操作 | 面试加分点 | 实战场景 |
|---|---|---|---|---|---|
int |
整数类型 | 不可变 | + - * / // % ** |
Python 3 长整型不限大小,掌握位运算 | 航班编号、票价整数计算 |
float |
浮点数 | 不可变 | + - * / ** round() |
浮点数精度问题,decimal 高精度计算 |
航班票价、折扣计算 |
complex |
复数 | 不可变 | real, imag |
少用,多考数学理解 | 科学计算(航班优化算法可能用) |
bool |
布尔值 | 不可变 | and, or, not |
Python 内部实现为 int 子类 | 条件判断、航班状态标记 |
一、int —— 整数类型(Python 最强的数值类型)
1️⃣ 底层原理
-
Python 3 的
int是:
arbitrary precision integer(任意精度)
-
不存在溢出
-
本质是 多位数组 + 符号位
a = 10
b = a
a += 1
# b 仍然是 10(不可变对象)
📌 不可变 = 每次运算都会创建新对象
2️⃣ 常用 & 易忽略操作
+ - * / // % **
整除陷阱(重要)
-7 // 3 # -3 (向下取整,不是向 0)
3️⃣ 位运算(面试高频)
& # 按位与
| # 按位或
^ # 异或
<< # 左移
>> # 右移
面试点
-
x << 1 == x * 2 -
x & 1判断奇偶
def is_odd(x):
return x & 1
4️⃣ 实战(航班编号 / 计数)
flight_id = 102345
seat_count = 180
remaining = seat_count - booked
二、float —— 浮点数(最容易出 Bug)
1️⃣ 底层原理(非常重要)
-
遵循 IEEE 754
-
二进制无法精确表示大多数十进制小数
0.1 + 0.2 == 0.3 # False
📌 不是 Python 的问题,是 计算机世界的物理限制
2️⃣ 精度问题示例
price = 199.9
discount = 0.1
price * discount # 19.990000000000002
3️⃣ 正确处理金钱:decimal
from decimal import Decimal
price = Decimal("199.9")
discount = Decimal("0.1")
price * discount # 精确
📌 面试加分点:
涉及钱,一定不用 float
4️⃣ round() 陷阱
round(2.5) # 2
round(3.5) # 4
👉 银行家舍入法(round half to even)
5️⃣ 实战(票价、折扣)
final_price = round(price * discount, 2)
三、complex —— 复数(冷门但能加分)
1️⃣ 基本结构
z = 3 + 4j
z.real # 3.0
z.imag # 4.0
2️⃣ 运算支持
(1+2j) * (3+4j)
abs(3+4j) # 模长 = 5
3️⃣ 面试加分点
-
Python 内建支持复数
-
不能比较大小
(1+2j) > (3+4j) # TypeError
4️⃣ 实战(理论场景)
-
信号处理
-
优化算法
-
路径规划数学模型
📌 业务系统很少用,但你知道就是优势
四、bool —— 布尔值(最容易被忽视)
1️⃣ 本质
isinstance(True, int) # True
等价关系
True == 1
False == 0
📌 bool 是 int 的子类
2️⃣ 运算特性
True + True # 2
False * 10 # 0
👉 很多计数逻辑直接利用这一点
3️⃣ 逻辑短路
a and b
a or b
-
and:第一个 False 就停 -
or:第一个 True 就停
user and user.is_active
4️⃣ 真值判断规则
False 的情况
False
0
0.0
''
[]
{}
None
5️⃣ 实战(航班状态)
is_delayed = False
is_cancelled = True
if is_cancelled or is_delayed:
notify_passengers()
2️⃣ 序列类型(Sequence)
| 类型 | 核心特性 | 可变性 | 常用操作 | 面试加分点 | 实战场景 |
|---|---|---|---|---|---|
list |
有序、可重复 | 可变 | append, extend, insert, pop, remove, sort |
切片 lst[start:end:step],列表推导式 |
航班列表存储、票价列表 |
tuple |
有序、可重复 | 不可变 | index, count |
元组解包,节省内存 | 航班固定信息组合 (航班号, 日期) |
range |
有序、不可重复 | 不可变 | range(start, stop, step) |
延迟生成数字序列,占用内存少 | 航班循环编号生成 |
str |
字符串 | 不可变 | split, join, strip, replace, find |
f-string, encode/decode | 航班号、乘客姓名 |
一、list —— 万能容器,但“可变=风险”
1️⃣ 核心原理
-
动态数组
-
连续内存 + 扩容机制(通常 1.125~2 倍)
lst = [1, 2, 3]
lst.append(4) # 原地修改
📌 可变对象,传参极易出 Bug
2️⃣ 高频操作 & 本质
append(x) # O(1) 均摊
extend(iter) # 批量追加
insert(i,x) # O(n)
pop(i) # O(n)
remove(x) # O(n)
sort() # 原地排序
3️⃣ 切片
lst[start:end:step]
⚠️ 切片返回新 list
a = lst[:]
a is lst # False
4️⃣ 列表推导式
a = lst[:]
a is lst # False
📌 可读性 + 性能都优于 for
5️⃣ 实战(航班列表)
flights = []
flights.append("MU1234")
flights.sort()
二、tuple —— 安全、快、适合“结构化数据”
1️⃣ 核心原理
-
不可变对象
-
存储的是 引用不可变
t = (1, [2, 3])
t[1].append(4) # 不报错
📌 不可变 ≠ 内容不可变
2️⃣ 元组解包
flight_no, date = ("MU1234", "2026-01-08")
高级用法:
a, *b, c = (1,2,3,4,5)
3️⃣ 面试加分点
-
比 list 更省内存
[list 对象头]
+ size 当前元素个数
+ allocated 已分配容量(>= size)
+ 指针数组 指向元素的指针[tuple 对象头]
+ size 固定长度
+ 指针数组 正好 size 个
tuple 是定长、不可变序列,
底层结构比 list 简单,
不需要维护扩容容量和多余空间,
所以在 CPython 中比 list 占用更少内存,
同时遍历性能也更好。
-
可作为 dict key(前提:元素可 hash)
d = {("MU1234", "2026-01-08"): 100}
4️⃣ 实战(固定航班信息)
flight = ("MU1234", "2026-01-08", "SHA", "PEK")
三、range —— 隐形高手(懒加载)
1️⃣ 核心原理
-
不存数据
-
只存:start / stop / step
r = range(1, 1_000_000_000)
📌 几乎不占内存
2️⃣ 特性
-
有序
-
不重复
-
支持切片(仍是 range)
range(10)[2:8:2]
3️⃣ 面试加分点
i in range(1000000000) # O(1)
👉 不遍历,而是数学计算
4️⃣ 实战(编号生成)
for i in range(1000, 1100):
generate_flight_no(i)
3️⃣ 集合类型(Set)
| 类型 | 核心特性 | 可变性 | 常用操作 | 面试加分点 | 实战场景 |
|---|---|---|---|---|---|
set |
无序、唯一
|
可变 | add, remove, union, intersection, difference |
集合运算效率高,hash 特性
|
存储已售票航班号,快速去重 |
frozenset |
|
不可变 | union, intersection |
可作为 dict key | 固定航班组合标识 |
4️⃣ 映射类型(Mapping)
| 类型 | 核心特性 | 可变性 | 常用操作 | 面试加分点 | 实战场景 |
|---|---|---|---|---|---|
dict |
|
可变 | get, setdefault, pop, keys, values, items |
|
航班信息存储 {"航班号": "状态"} |
collections.OrderedDict |
有序字典 | 可变 | 保持插入顺序 | Python 3.7+,普通 dict 已默认有序 | 有序航班列表 |
defaultdict |
key 不存在 → 自动创建 | 可变 | 自动初始化 key | 避免 KeyError | 航班票价分类统计 |
5️⃣ 二进制类型(Binary)
| 类型 | 核心特性 | 可变性 | 常用操作 | 面试加分点 | 实战场景 |
|---|---|---|---|---|---|
bytes |
不可变字节序列 | 不可变 | b'abc', decode, split |
字符编码、网络传输 | 航班 API 数据传输 |
bytearray |
可变字节序列 | 可变 | append, extend |
网络/文件操作 | 二进制缓存处理 |
memoryview |
内存视图 | 可变 | cast |
零拷贝,节省内存 | 大规模航班数据处理 |
6️⃣ 面试连环题
可变 vs 不可变:理解引用、拷贝行为
在 Python 中,变量并不直接保存数据本身,而是保存对象的引用。不可变对象(如 int、str、tuple)一旦创建,其内部值就不能被修改,任何“修改操作”本质上都会创建一个新对象并让变量指向新的引用;因此多个变量指向同一个不可变对象时,不会因为其中一个变量的运算而影响其他变量。相反,可变对象(如 list、dict、set)允许原地修改内容,当多个变量引用同一个可变对象时,对其中任意一个变量的修改,都会反映到所有引用该对象的地方,这也是可变对象在共享场景下最容易引发 Bug 的根源。
理解拷贝行为的关键在于区分“拷贝引用”还是“拷贝对象”。对不可变对象而言,所谓拷贝通常只是增加一个新的引用指向同一个对象,因为对象本身无法被修改,复用是安全的;而对可变对象,直接赋值或浅拷贝(如 list[:]、copy.copy)只会创建一个新的容器,但容器内部的元素仍然是对原对象中元素的引用,一旦内部元素本身也是可变的,修改就会相互影响。只有深拷贝(copy.deepcopy)才会递归地复制所有层级的对象,从而实现真正意义上的“完全独立”,这也是在复杂业务和并发场景中隔离状态时必须慎重选择的拷贝方式。
为什么 x in set 比 x in list 快?
-
list:顺序遍历 → O(n) -
set:hash 定位 → O(1)
set 底层是 hash table,本质是 dict 的 key。
set 为什么无序?Python 3.7+ dict 却有序?
-
set:只关心 hash 分布
-
dict:在 hash table 之外维护插入顺序数组
dict 是“有序的 hash table”,set 不是。
set 里为什么不能放 list?
{[1,2]} # TypeError
-
set 元素必须 可 hash
-
list 可变 → hash 值不稳定
hash 的前提是不可变。
dict 查找一定是 O(1) 吗?
-
平均 O(1)
-
极端 hash 冲突 → O(n)
-
hash 是什么?
-
Python 如何解决 hash 冲突?
-
rehash(扩容)什么时候发生?
Python 使用开放寻址法 + 动态扩容,极端情况已被极大避免。
一、什么是开放寻址法(Open Addressing)
冲突了,不建链表,继续找下一个空位
Python 的
dict和set在底层使用开放寻址法(Open Addressing)来解决 hash 冲突。当一个 key 经过 hash 计算后映射到的槽位已经被占用时,并不会像链表法那样在该位置挂链表,而是按照一套探测规则(扰动探测序列)继续在同一个数组中寻找下一个可用槽位。所有 key 都存放在一块连续的内存中,这种设计减少了指针跳转,提高了 CPU cache 命中率,使得查找、插入和删除在平均情况下都能保持接近 O(1) 的性能。二、动态扩容(rehash)
为什么一定要扩容?
由于开放寻址法在表过满时探测成本会急剧上升,Python 为
dict和set设计了动态扩容机制。当哈希表的装载因子超过一定阈值(约为 2/3)时,系统会触发 rehash:申请一块更大的连续内存作为新表,然后将旧表中的所有 key 重新计算位置并插入到新表中。通过这种“低装载因子 + 扩容重排”的策略,Python 能有效避免性能退化,保证在数据量不断增长的情况下,哈希表操作依然稳定高效。扩容过程
1. 申请更大的 table(通常 ×2)
2. 遍历旧 table
3. 对每个 key 重新 hash
4. 插入新 table
7️⃣ 航班系统【完整数据结构选型表】
| 场景 | 类型 | 原因 |
|---|---|---|
| 航班列表 | list | 有序、可遍历 |
| 固定航班信息 | tuple | 不可变、安全 |
| 航班编号生成 | range | 省内存 |
| 已售航班号 | set | O(1) 查重 |
| 航线组合 | frozenset | 无序 + 可 hash |
| 航班状态 | dict | key-value |
| 有序航班缓存 | OrderedDict | move_to_end |
| 票价统计 | defaultdict(int) | 自动初始化 |
| 航班信息存储 | dict |
key-value 快速访问 |
| 售票用户集合 | set |
去重快速查找 |
| 不可修改的航班组合 | tuple / frozenset |
不可变,保证安全 |
| 大批量航班数据迭代 | generator |
节省内存,按需生成 |
| 二进制 API 数据 | bytes / bytearray |
网络传输和缓存处理 |
不推荐搭配
| 反例 | 原因 |
|---|---|
| list 查重 | O(n) |
| dict 当队列 | pop 慢 |
| defaultdict 存业务数据 | 隐式创建 |
| set 存顺序数据 | 顺序丢失 |
Python 基础
1️⃣Python 数据类型 & 内存管理
| 题目 | 核心答案 | 底层原理 | 面试加分点 | 典型坑 | 实战案例 |
|---|---|---|---|---|---|
| list 和 tuple 区别 | list 可变,tuple 不可变 | list 底层动态数组;tuple 固定大小,连续内存 | tuple 可 hash,可做 dict key,内存更小 | 不可修改 tuple 内部对象;tuple 内嵌可变对象仍可修改 | 坐标点保存为 tuple,节省百万条数据内存 |
| dict 查找复杂度 | 平均 O(1),最坏 O(n) | 哈希表实现;Py3.6+ dict 有插入顺序 | 讲解 hash 冲突解决:开放寻址或红黑树 | hash 冲突导致最坏情况 O(n) | 用户 ID 映射信息查找 |
| set 和 dict 区别 | set 只有 key,没有 value,都是哈希表 | 底层和 dict 类似 | set 运算:交集、并集、差集 | set 中元素必须可 hash,否则报错 | 去重用户列表 |
| 浅拷贝 vs 深拷贝 | 浅拷贝只复制引用,深拷贝递归复制 | copy 模块底层实现 浅拷贝: 创建新对象,其内容是原对象的引用。 深拷贝:和浅拷贝对应,深拷贝拷贝了对象的所有元素,包括多层嵌套的元素。深拷贝出来的对象是一个全新的对象,不再与原来的对象有任何关联。 |
对嵌套结构理解,避免共享副作用 | 浅拷贝嵌套可变对象会被修改 | 复制航班票价结构体 |
| 可变 vs 不可变对象 | 可变对象传入函数会修改,immutable 不会 | 内存引用 + 栈帧 | 对函数参数传递理解 | 使用 immutable 做 key 时需确保不可变 | 配置 dict vs tuple key 缓存结果 |
| 内存管理与 GC | 引用计数 + 循环引用垃圾回收 | PyObject 引用计数,gc 模块触发代际回收 |
gc.collect() 强制回收 | 循环引用导致内存泄漏 | 大批量订单对象处理 |
Python GC主要使用引用计数(reference counting)来跟踪和回收垃圾。在引用计数的基础上,通过“标记-清除”(mark and sweep)解决容器对象可能产生的循环引用问题,通过“分代回收”(generation collection)以空间换时间的方法提高垃圾回收效率。
1 引用计数
PyObject是每个对象必有的内容,其中ob_refcnt就是做为引用计数。当一个对象有新的引用时,它的ob_refcnt就会增加,当引用它的对象被删除,它的ob_refcnt就会减少.引用计数为0时,该对象生命就结束了。
优点:
- 简单
- 实时性
缺点:
- 维护引用计数消耗资源
- 循环引用
2 标记-清除机制
基本思路是先按需分配,等到没有空闲内存的时候从寄存器和程序栈上的引用出发,遍历以对象为节点、以引用为边构成的图,把所有可以访问到的对象打上标记,然后清扫一遍内存空间,把所有没标记的对象释放。
3 分代技术
分代回收的整体思想是:将系统中的所有内存块根据其存活时间划分为不同的集合,每个集合就成为一个“代”,垃圾收集频率随着“代”的存活时间的增大而减小,存活时间通常利用经过几次垃圾回收来度量。
Python默认定义了三代对象集合,索引数越大,对象存活时间越长。
举例: 当某些内存块M经过了3次垃圾收集的清洗之后还存活时,我们就将内存块M划到一个集合A中去,而新分配的内存都划分到集合B中去。当垃圾收集开始工作时,大多数情况都只对集合B进行垃圾回收,而对集合A进行垃圾回收要隔相当长一段时间后才进行,这就使得垃圾收集机制需要处理的内存少了,效率自然就提高了。在这个过程中,集合B中的某些内存块由于存活时间长而会被转移到集合A中,当然,集合A中实际上也存在一些垃圾,这些垃圾的回收会因为这种分代的机制而被延迟。
2️⃣函数、闭包、装饰器
| 题目 | 核心答案 | 底层原理 | 面试加分点 | 典型坑 | 实战案例 |
|---|---|---|---|---|---|
| 参数传递 | Python 传对象引用,mutable 会修改 | 栈帧存储引用,函数局部不复制对象 | 对 list/dict/int 不同表现理解 | mutable 被意外修改 | API 配置 dict 传入多个函数 |
| *args / **kwargs | *args → tuple, **kwargs → dict | Python 可变参数实现 | 调用灵活 | 拼写错误导致收集不到参数 | 通用函数包装任意参数 API |
| 闭包 | 内层函数引用外层变量形成闭包 | closure 保存外层变量 cell 对象 | 使用 nonlocal 修改外层变量 | 闭包引用循环引用造成内存问题 | 装饰器缓存内部状态 |
| 装饰器 | 函数套函数,返回新函数,@语法糖 | 闭包 + 高阶函数 | functools.wraps 保留元信息 | 多层装饰器顺序错误 | 权限校验、缓存、日志装饰器 |
| lambda | 匿名函数,单表达式 | 编译为函数对象 | 搭配 map/filter/comprehension | 单表达式限制 | 列表字段提取 |
3️⃣并发与异步
| 题目 | 核心答案 | 底层原理 | 面试加分点 | 典型坑 | 实战案例 |
|---|---|---|---|---|---|
| threading vs multiprocessing | threading 受 GIL 限制,多用于 IO,multiprocessing 真并行 | GIL 只允许一个线程执行字节码,进程有独立 GIL | 选择适用场景 | CPU 密集型用 thread 会慢 | 高并发 HTTP 请求 vs 数据计算 |
| asyncio | 单线程事件循环协程切换 | Event Loop + Task Scheduling | async/await | 忘记 await,任务不执行 | 异步爬虫、异步 API 调用 |
| queue / asyncio.Queue | 线程安全 / 协程安全 | 内部锁机制 | 生产者-消费者模式 | 阻塞与非阻塞使用混乱 | 日志异步写入 |
| futures / concurrent.futures | 封装线程池/进程池 | submit/map 任务调度 | 任务结果异步获取 | 忘记 shutdown 导致进程泄露 | 并行数据处理 |
4️⃣ 面向切面编程AOP和装饰器
这个AOP一听起来有点懵,同学面阿里的时候就被问懵了...
装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志、性能测试、事务处理等。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量函数中与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
AOP 是 面向切面编程(Aspect-Oriented Programming) 的缩写。它是一种 程序设计思想,用于 将程序中的横切关注点(cross-cutting concerns)从业务逻辑中分离出来,让核心业务逻辑更清晰,同时可复用、可维护。
1️⃣ 核心概念
| 概念 | 解释 |
|---|---|
| 切面(Aspect) | 横切关注点的封装,例如日志、事务、安全校验 |
| 连接点(Join point) | 程序执行中的一个点,比如方法调用、异常抛出 |
| 通知(Advice) | 在连接点上执行的操作,可以是: - 前置通知(Before) - 后置通知(After) - 环绕通知(Around) |
| 切入点(Pointcut) | 指定哪些连接点需要被通知 |
| 目标对象(Target) | 被增强的业务对象 |
| 织入(Weaving) | 将切面应用到目标对象的过程 |
2️⃣ 作用
-
解耦:日志、事务、安全检查等不污染核心业务逻辑
-
复用:同一个切面可以应用到多个类或方法
-
统一管理:系统级功能集中管理,提高维护性
3️⃣ 典型场景
| 场景 |
|---|
1575



被折叠的 条评论
为什么被折叠?



