Python 的 int 为什么不会溢出?拆开 PyLongObject 和它背后那串变长数组

你有没有试过在 Python 里算 2 ** 10000?它不会像 C 那样默默变成 0,也不会抛异常,而是老老实实吐出一长串数字。很多人说"Python 的 int 没有上限",这句话对,但它真正的代价藏在内存里。今天我把 CPython 的整数对象拆开,看看它为了"永不溢出"到底付出了什么。

一、先说一个反直觉的小事实

在 Python 启动的那一刻,解释器就偷偷把 -5 到 256 这 262 个整数全部预先建好缓存起来了。你可以验证:

python 复制代码
a = 256
b = 256
print(a is b)   # True,指向同一个对象
x = 257
y = 257
print(x is y)   # 在多数交互环境里是 False,每次都是新对象

这意味着"小整数"几乎不占额外内存,而且比较 is 还能命中同一个对象。这一个细节,是很多人优化热点循环时忽略的第一点------反复创建 257 以上的小整数,其实在不断 malloc 新对象。

二、PyLongObject 到底是什么

CPython 源码里,整数对象的核心是这么个结构(简化):

c 复制代码
struct _longobject {
    PyObject_VAR_HEAD
    int ob_digit[1];   // 变长数组,每一位存 30 个二进制位
};

关键点有三个,我一个一个说:

  1. ob_size 同时编码"长度"和"符号"。它是负数表示这个整数是负的,绝对值才是数组长度。一个字段干了两件事,这是 C 里常见的省内存技巧。
  2. ob_digit 不是按"字节"存的,而是按 30 位(64 位平台上)一块一块存 。也就是说,一个 digit 是 30 个二进制位,而不是 8 个。这样做是为了在 32 位整型里留足余量做乘法进位,避免溢出。
  3. 数组是变长的。小数字只需要 1 个 digit,大数字就不断追加。这就是"永不溢出"的真相------不够就加 digit,直到内存用完。

三、实测:一个整数到底占多少内存

我在一台 Python 3.13(64 位)上跑了 sys.getsizeof,看不同量级整数占用的字节:

数值 二进制位数 估算 digit 数 实际 sizeof
0 0 0 28 B
255 8 1 28 B
2**30 31 2 32 B
2**60 61 3 36 B
2**100 101 4 40 B
2**525 525 18 96 B
2**1000 1001 34 160 B

注意看:2**1000 是 1001 个二进制位,理论上 1001/8 ≈ 126 字节就够了,但实际是 160 字节 。多出来的部分,一部分是 30 位对齐的浪费(每个 digit 实际占 4 字节即 32 位,有 2 位闲着),另一部分是对象头 PyObject_VAR_HEAD 的固定开销(28 字节起)。

我个人的判断是 :这个设计在"小整数"上极度省(28 字节封顶),但在"几百位以上的大整数"上,相对理论最小编码有约 20%~30% 的冗余。对绝大多数业务来说无所谓,但如果你在内存里塞了几百万个大素数,这个冗余就值得换方案了(比如直接用 gmpy2 的 mpz)。

四、和别的语言比一比

类型 上限 溢出行为 内存
C long (64位) ±9.2×10¹⁸ 静默回绕 8 字节固定
Java BigInteger 无限 不溢出 变长,类似思路
Python int 无限 不溢出 28B 起,变长

C 快但会溢出(还静默),Java 和 Python 都走"变长"路线保证正确,代价就是慢一点、占内存多一点。

五、三个最容易踩的坑

  1. 别拿 is 比较大整数 。只有 -5~256 有缓存,超出范围 is 结果不可靠,老老实实用 ==。
  2. 大整数运算慢 。每一位都要做 30 位乘法和进位处理,2**100000 的乘法比你想的贵得多。
  3. sys.getsizeof 只算对象本身,如果你把大整数放进列表,列表里存的只是指针,整数对象的内存是另算的------这点做内存评估时经常漏。

结语

Python 的 int 不会溢出,不是魔法,是"用内存换正确性"的取舍:一个 30 位的变长数组 + 复用的对象头。小数字几乎白送,大数字按位计费。理解这一点,你就不会再奇怪为什么 2**1000 是 160 字节,也不会再误用 is 去比较整数了。

相关推荐
威哥爱编程2 小时前
Python 智能体开发实战 03:聊十轮就“失忆”,账单还翻倍?管好上下文,Token 立省一半
python·agent
情 九2 小时前
MCP 开发环境搭建:Mac 与 Windows 跑通 Python 服务和 stdio 客户端
windows·python·macos·mcp
SEO_juper2 小时前
Bash 交叉验证 robots.txt 和 sitemap:两个文件自相矛盾,页面永远收录不了
开发语言·python·node.js·json·bash
日日大王学编程2 小时前
LangGraph 基本用法详解:从入门到实战
python·语言模型·langchain
威哥爱编程2 小时前
Python 智能体开发实战 04:模型答得挺漂亮,程序却读不懂?让回答直接变成能入库的 JSON
python·agent
全栈陈序员2 小时前
【Python】基础语法入门(三十)—— Web 开发入门:用 Flask 搭建第一个网站
前端·python·flask
全栈陈序员2 小时前
【Python】基础语法入门(三十三)—— 日志系统详解:用 logging 记录程序运行
java·开发语言·python
晗夜未央2 小时前
跨仓库 Skill 换台电脑就失效?用 Git remote 校验项目
人工智能·git·python
Zack_Liu3 小时前
code样例
pytorch·python·深度学习