基本数据类型的底层实现
1. 整数 (int)
语法:
x = 10
y = -5
z = 0
large_num = 1_000_000 # 使用下划线提高可读性
底层实现:
- Python 3 的 int 是任意精度整数
- 使用 C 语言的
PyLongObject结构体 - 内部使用数字数组表示大整数
- 小整数 (-5 到 256) 有缓存机制
# 底层结构示意
class PyLongObject:
ob_refcnt # 引用计数
ob_type # 类型指针
ob_size # 数字的位数(绝对值)
ob_digit[0] # 数字数组(实际存储)
内存布局:
小整数: 直接存储在对象头中
大整数: 对象头 + 动态分配的数字数组
2. 浮点数 (float)
语法:
a = 3.14
b = -2.5
c = 1.0
scientific = 1.23e-4 # 科学计数法
底层实现:
- 基于 C 语言的
double类型(双精度浮点数) - 使用 IEEE 754 标准
- 64位表示:1位符号 + 11位指数 + 52位尾数
# 浮点数精度问题(所有语言通用)
print(0.1 + 0.2 == 0.3) # False
print(0.1 + 0.2) # 0.30000000000000004
3. 布尔值 (bool)
语法:
is_valid = True
is_done = False
底层实现:
- 实际上是 int 的子类
True == 1,False == 0- 单例模式,只有两个实例
print(issubclass(bool, int)) # True
print(True + 1) # 2
print(False * 5) # 0
4. 字符串 (str)
语法:
s1 = "hello"
s2 = 'world'
s3 = """多行
字符串"""
s4 = r"原始字符串\n不转义" # raw string
底层实现:
- Python 3 使用 Unicode (UTF-8) 编码
- 内部结构优化:
- 紧凑字符串(Python 3.3+)
- 字符串驻留(小字符串缓存)
// C 底层结构
typedef struct {
PyObject_HEAD
Py_ssize_t length; // 字符串长度
Py_hash_t hash; // 缓存哈希值
struct {
unsigned int interned:2; // 驻留状态
unsigned int kind:3; // 字符宽度(1,2,4字节)
unsigned int compact:1; // 紧凑标志
unsigned int ascii:1; // ASCII 标志
unsigned int ready:1; // 就绪标志
} state;
wchar_t *wstr; // 宽字符表示
} PyUnicodeObject;
容器类型的底层实现
1. 列表 (list)
语法:
lst = [1, 2, 3, "hello"]
lst.append(4)
lst[0] = 10
底层实现:
- 动态数组(可扩容的指针数组)
- 过度分配策略:分配比实际需要更多的空间
// C 底层结构
typedef struct {
PyObject_VAR_HEAD
PyObject **ob_item; // 指向元素指针数组的指针
Py_ssize_t allocated; // 已分配的空间数量
} PyListObject;
内存增长策略:
# 扩容公式:new_allocated = (size + (size >> 3) + 6) & ~3
# 示例增长序列:0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ...
2. 元组 (tuple)
语法:
tup = (1, 2, 3, "hello")
single = (42,) # 单元素元组需要逗号
底层实现:
- 固定大小的数组
- 比列表更节省内存(无过度分配)
- 小元组缓存机制
// C 底层结构
typedef struct {
PyObject_VAR_HEAD
PyObject *ob_item[1]; // 柔性数组成员
} PyTupleObject;
3. 字典 (dict)
语法:
d = {"name": "Alice", "age": 30}
d["city"] = "New York"
底层实现:
- 哈希表(开放定址法)
- Python 3.6+ 保持插入顺序
- 结合稀疏表和紧凑表
// C 底层结构(简化)
typedef struct {
Py_ssize_t me_hash; // 键的哈希值缓存
PyObject *me_key; // 键
PyObject *me_value; // 值
} PyDictKeyEntry;
typedef struct _dictkeysobject {
Py_ssize_t dk_refcnt;
Py_ssize_t dk_size; // 哈希表大小
Py_ssize_t dk_usable; // 可用条目数
Py_ssize_t dk_nentries; // 已用条目数
PyDictKeyEntry dk_entries[1]; // 条目数组
} PyDictKeysObject;
哈希表解决冲突:
# 探测序列:index = hash(key) & mask
# 如果冲突:index = (5 * index + 1 + perturb) & mask
4. 集合 (set)
语法:
s = {1, 2, 3, 4}
s.add(5)
底层实现:
- 基于字典实现,只有键没有值
- 使用相同的哈希表机制
// C 底层结构
typedef struct {
PyObject_HEAD
PyObject *weakreflist;
Py_ssize_t fill; // 活跃 + 假删除条目数
Py_ssize_t used; // 活跃条目数
Py_ssize_t mask; // 掩码 = 表大小 - 1
setentry *table; // 哈希表
Py_ssize_t finger; // 搜索指纹
setentry smalltable[8]; // 小集合优化
Py_hash_t hash; // 仅用于冻结集合
Py_ssize_t num_active; // 仅用于冻结集合
} PySetObject;
内存管理和优化
1. 小对象缓存
# 小整数缓存 (-5 到 256)
a = 100
b = 100
print(a is b) # True - 同一个对象
# 字符串驻留
s1 = "hello"
s2 = "hello"
print(s1 is s2) # True - 同一个对象
# 空元组单例
t1 = ()
t2 = ()
print(t1 is t2) # True
2. 对象头开销
每个 Python 对象都有对象头:
typedef struct _object {
Py_ssize_t ob_refcnt; // 引用计数(8字节)
PyTypeObject *ob_type; // 类型指针(8字节)
} PyObject;
各种类型的内存占用:
import sys
print(f"int: {sys.getsizeof(0)} bytes") # 24 bytes
print(f"float: {sys.getsizeof(0.0)} bytes") # 24 bytes
print(f"bool: {sys.getsizeof(True)} bytes") # 24 bytes
print(f"空列表: {sys.getsizeof([])} bytes") # 56 bytes
print(f"空字典: {sys.getsizeof({{}})} bytes") # 64 bytes
3. 可变 vs 不可变类型
不可变类型: int, float, bool, str, tuple, frozenset
- 创建后不能修改
- 可哈希,可作为字典键
- 线程安全
可变类型: list, dict, set, bytearray
- 创建后可修改
- 不可哈希,不能作为字典键
- 线程不安全
性能特点总结
| 类型 | 时间复杂度 | 空间效率 | 使用场景 |
|---|---|---|---|
| list | O(1) 索引,O(n) 插入删除 | 中等 | 有序集合,频繁索引 |
| tuple | O(1) 索引 | 高 | 固定数据,字典键 |
| dict | O(1) 查找插入删除 | 低 | 键值映射,快速查找 |
| set | O(1) 查找插入删除 | 低 | 去重,成员测试 |
| str | O(1) 索引,O(n) 拼接 | 高 | 文本处理 |
