『Python底层原理』--Python整数为什么可以无限大
整数类型是编程中最常见的数据类型之一,但它的实现细节却鲜为人知。
与其他语言不同,Python 的整数是任意精度的,这意味着它们可以无限大,仅受限于内存。
这种特性使得 Python 在处理大整数时非常强大,但也增加了实现的复杂性。
今天,我们将探讨 Python 整数的内部实现,揭示其背后的奥秘。
1. 整数的内部表示
在大多数编程语言中,整数通常是固定精度的,例如 32 位或 64 位。
然而,Python 的整数是任意精度的,这意味着它们可以无限大,而不会出现溢出问题。
这种特性使得 Python在密码学、计算机代数等领域中非常实用。
# Python 中的整数可以非常大,而不会溢出
big_number = 1234567890123456789012345678901234567890
print(big_number * big_number) # 输出一个更大的整数
这种任意精度的特性是如何实现的呢?
答案在于 Python 的整数实现方式。
Python 的整数是通过 CPython 的 PyLongObject 结构体实现的,
这个结构体定义了整数的存储方式,包括符号和数字。
PyLongObject的定义参考:Include/cpython/longintrepr.h 文件。
typedef struct _PyLongValue {
uintptr_t lv_tag; /* Number of digits, sign and flags */
digit ob_digit[1];
} _PyLongValue;
struct _longobject {
PyObject_HEAD
_PyLongValue long_value;
};
这里的_longobject就是PyLongObject,_PyLongValue中存储了数字的符号和个数。
Python 使用一种“大基数”表示法,而不是常见的十进制表示,
在 64 位平台上,基数为\(2^{30}\) ,而在 32 位平台上,基数为\(2^{15}\) 。
以64位平台(基数为$ 2^{30} $)为例,一个大数据1234567890123456789存储为[1038713109, 76039121, 1]。
def to_digits(n, base=2**30):
digits = [n % base]
n = n // base
while n != 0:
digits.append(n % base)
n = n // base
return digits
x = 1234567890123456789
print(f"整数 {x} 的底层数字表示: {to_digits(x)}")
# 整数 1234567890123456789 的底层数字表示: [1038713109, 76039121, 1]
如果要计算在32位平台上的表示,只要将传入to_digits的base参数改为2**15即可。
所以,任意大的整数,在Python内部都用用一个列表来存放,列表中的每个数值都小于$ 2^{30} \(或者\) 2^{15} $。
2. 整数的内存优化
Python 整数占用较多内存,即使是小整数也需要 28 字节(在 64 位平台上)。
为了优化内存使用,CPython 采取了一些巧妙的策略,尤其是在处理小整数时。
我本机上的Python3.12.4版本中,小于等于$ 2^{64} $的整数都是缓存的。
i = 2**64
j = 2**64
print(f"addr i: {id(i)}, addr j: {id(j)}")
print(f"i 和 j 是否相同: {i is j}")
# addr i: 2595289736288, addr j: 2595289736288
# i 和 j 是否相同: True
i = 2**65
j = 2**65
print(f"addr i: {id(i)}, addr j: {id(j)}")
print(f"i 和 j 是否相同: {i is j}")
# addr i: 2595289736432, addr j: 2595289736480
# i 和 j 是否相同: False
从上面的示例可以看出,当整数$ \le 2^{64} $时,i和j的内存地址是一样的;反之则不一样。
不过,虽然CPython对整数的实现已经很高效了,但是但在处理大量整数时,内存占用仍然是一个需要考虑的问题。
以下是一些优化建议:
- 使用
array模块或numpy:如果你需要存储大量同类型的整数,使用array模块或numpy会以更紧凑的方式存储数据。 - 避免不必要的整数创建:尽量复用已有的整数对象,尤其是在循环中。
- 使用生成器:如果只需要逐个处理整数,可以使用生成器而不是创建整个列表。
3. 整数的性能优化
CPython的整数实现不仅考虑了内存使用,还通过多种优化手段提高了运算性能。
- 位操作优化:对于大整数,
CPython使用多精度算术,多精度整数在内存中以数组形式存储,每个元素代表一定位数的数值。
关联的源码可参考:Include/cpython/longintrepr.h 和 Objects/longobject.c
- 缓存机制优化:对于一些频繁出现的运算或者中间结果,会将其缓存起来。当再次需要这些结果时,直接从缓存中获取,而不是重新计算。
关联的源码可参考:Objects/longobject.c 和 Objects/object.c
- 并行计算支持:对于大整数加法,会将计算任务分解成多个子任务,并行地在多个核心上执行。
关联的源码可参考:Python/thread_pthread.h、Python/thread_pthread.c 和 Objects/longobject.c
- 代码生成优化:在将整数加法的
Python代码转换为机器码时,生成更高效的指令序列。
关联的源码可参考:Python/compile.c和Python/ceval.c
4. 总结
Python 的整数实现是一个高效且灵活的任意精度整数系统。
通过CPython的源码,我们可以看到Python如何在内部处理大整数,以及如何通过优化策略提高性能和节省内存。
不过,虽然Python的整数实现已经非常强大,但在处理大量数据时,我们仍然可以通过一些技巧进一步优化内存使用和性能。
『Python底层原理』--Python整数为什么可以无限大的更多相关文章
- 操作系统底层原理与Python中socket解读
目录 操作系统底层原理 网络通信原理 网络基础架构 局域网与交换机/网络常见术语 OSI七层协议 TCP/IP五层模型讲解 Python中Socket模块解读 TCP协议和UDP协议 操作系统底层原理 ...
- 『无为则无心』Python日志 — 64、Python日志模块logging介绍
目录 1.日志的作用 2.为什么需要写日志 3.Python中的日志处理 (1)logging模块介绍 (2)logging模块的四大组件 (3)logging日志级别 1.日志的作用 从事与软件相关 ...
- 『无为则无心』Python基础 — 3、搭建Python开发环境
目录 1.Python开发环境介绍 2.Python解释器的分类 3.下载Python解释器 4.安装Python解释器 5.Python解释器验证 1.Python开发环境介绍 所谓"工欲 ...
- 『无为则无心』Python基础 — 4、Python代码常用调试工具
目录 1.Python的交互模式 2.IDLE工具使用说明 3.Sublime3工具的安装与配置 (1)Sublime3的安装 (2)Sublime3的配置 4.使用Sublime编写并调试Pytho ...
- 『无为则无心』Python函数 — 34、lambda表达式
目录 1.lambda的应用场景 2.lambda语法 3.快速入门 4.示例:计算a + b 5.lambda的参数形式 6.lambda的应用 lambda表达式的主要作用就是化简代码. 匿名函数 ...
- 『无为则无心』Python面向对象 — 46、类和对象
目录 1.理解类和对象 2.类 3.对象 4.Python中的对象 5.类和对象的定义 (1)定义类 (2)创建对象 (3)练习 6.拓展:isinstance() 函数 1.理解类和对象 (1)类和 ...
- python底层原理
有同学问到了一个问题,python中存储变量是通过内存地址来存储,那么python又是如何去判断内存中的地址是什么数据类型的呢.经过查找,找到这篇文章: 原博客地址:http://www.cnblog ...
- Python 底层原理知识
1.Python是如何进行内存管理的? 答:从三个方面来说,一对象的引用计数机制,二垃圾回收机制,三内存池机制 一.对象的引用计数机制 Python内部使用引用计数,来保持追踪内存中的对象,所有对象都 ...
- 『无为则无心』Python基础 — 2、编译型语言和解释型语言的区别
目录 1.什么是计算机语言 2.高级语言中的编译型语言和解释型语言 (1)编译型语言 (2)解释型语言 (3)编译型语言和解释型语言执行流程 3.知识扩展: 4.关于Python 1.什么是计算机语言 ...
- 『无为则无心』Python基础 — 7、Python的变量
目录 1.变量的定义 2.Python变量说明 3.Python中定义变量 (1)定义语法 (2)标识符定义规则 (3)内置关键字 (4)标识符命名习惯 4.使用变量 1.变量的定义 程序中,数据都是 ...
随机推荐
- rocketMQ集群部署
RocketMQ集群部署 RocketMQ是一款非常优秀的消息中间件,运用的场景也是非常丰富,且在各大公司运用中也非常广泛.但是它是如何进行部署的呢,以及它的高可用是如何实现的呢.那么就由我来为大家讲 ...
- Linux清理内存,清理储存
因为工作中项目部署服务器后更新迭代或者服务器使用时间长后会出现内存/储存爆满,所以整合了一下,方便以后使用: 清理虚拟内存 查看内存 free -h 清理缓存 输入命令释放内存 0 – 不释放 1 – ...
- windows安装gitbook并部署发布到openEuler欧拉服务器
1. 安装nodejs10 下载安装nvm https://github.com/coreybutler/nvm-windows/releases/download/1.1.9/nvm-setup.e ...
- HttpClient初步理解
昨天做完网站项目,就立刻接到了接口的项目,遇到了httpclient,因为毕业不久,遇到这块所以特此留下理解 HttpClient介绍 概念: HTTP 协议可能是现在 Internet 上使用得最多 ...
- 小程序 构建npm
1. 在项目文件夹下 打开cmd 窗口,输入: npm init 一直回车即可 2. 安装模板 npm i @vant/weapp -S --production 3. 在微信开发者工具,左上角工具中 ...
- Excel VLOOKUP 函数入门教程
一.引言 在日常工作中,Excel 是处理数据的强大工具之一,而 VLOOKUP 函数作为 Excel 中最常用的查找函数之一,能够帮助用户在表格或数值数组中快速定位并返回所需的数据.它的工作原理是在 ...
- 【uni-app】【01】底部导航栏与页面切换
1.(配置文件在哪)uni-app 路由控制是在 pages.json文件中的. 2.(基本配置项有哪些)初学的时候主要有三个配置项,①pages ② globalStyle ③ tabbar [!T ...
- 【MyBatis】学习笔记08:批量删除
[Mybatis]学习笔记01:连接数据库,实现增删改 [Mybatis]学习笔记02:实现简单的查 [MyBatis]学习笔记03:配置文件进一步解读(非常重要) [MyBatis]学习笔记04:配 ...
- mysql5.7以后group by 报错 sql_mode=only_full_group_by的解决方法
一.发现问题 1.查询语句 SELECT * from class group by class_name; 2.报错结果 ..... this is incompatible with sql_mo ...
- 【转载】 SpringBoot声明式事务的简单运用
https://blog.csdn.net/justry_deng/article/details/80828180 关于事物的基本概念等这里就不介绍了. Spring声明式事物的实现,有两种方式:第 ...