python中整型不会溢出,是因为cpython用pylongobject结构体实现,其ob_digit数组动态存储任意长度数字,低位在前、高位在后,每个digit存30位有效数据,内存足够即可无限扩展。

Python 中大整数相加不会溢出,是因为它根本不用 C 那套固定位宽的整数表示——int 类型在 CPython 里是动态结构体 PyLongObject,底层用变长数组 ob_digit 存数字,内存够就能无限扩。
Python 的 int 不是 C 的 int
你写 2**1000000 + 1 能立刻算出来,不是因为“优化得好”,而是因为它压根没用 CPU 的 64 位加法指令。CPython 把这个数拆成一串 digit(通常是 uint32_t),每个存 30 位有效数据(PyLong_SHIFT == 30),低位在前、高位在后,像这样:
[0x3a8, 0x1f4, 0x001, ...]
加法就是模拟小学竖式:逐位加、进位、动态扩容。所以不存在“超出范围”这回事——只要堆内存没耗尽,就不会崩溃或回绕。
ob_digit 数组怎么决定长度?
ob_digit 长度由 ob_size 字段控制,正负号也藏在这里(负数时 ob_size 为负)。比如存 1000000(约 20 位十进制):
- 在 64 位系统上,
PyLong_SHIFT == 30,意味着每个digit最多存 2³⁰−1 ≈ 10.7 亿 1000000 ,所以只需要 1 个 <code>digit元素 →ob_size == 1- 而
2**1000000需要约 ⌈1000000 × log₂(10) / 30⌉ ≈ 100300 个digit,ob_size就是那个数
这个长度完全运行时决定,不编译期固定。
为什么乘法/除法会明显变慢?
小整数(如 42)走快速路径,直接用 CPU 指令;一旦 ob_size > 1,所有运算都退化为 O(n²) 或更差的算法:
-
+和-是 O(n),n 是ob_digit长度 -
*默认用朴素乘法(O(n²)),超大数才切到 Karatsuba(O(n^log₂3)) -
//和%更重,涉及多次试商,复杂度接近 O(n²) 或更高 -
str()是最坑的——要把整个大数转十进制字符串,内部要反复做除法,实际是 O(n²) 甚至更差
所以不是“不会溢出就万能”,而是用可预测的性能下降换来了确定性行为。
和 C 的溢出行为对比时最容易忽略什么?
很多人以为“Python 不溢出 = 更安全”,但真正容易踩坑的是隐式类型切换和性能断层:
- 从
int到大整数没有提示,也不会警告,但timeit一测可能慢百倍 - C 的溢出是未定义行为(UB),可能静默错、崩溃、或依赖编译器优化;Python 的“不溢出”是明确定义的行为,但代价全在运行时
- 跨语言交互(如 ctypes、C extension)时,若把 Python 大整数传给期望
int64_t的 C 函数,会直接抛OverflowError,不是截断
真正关键的不是“能不能算”,而是“什么时候开始算得慢、以及慢多少”。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











