Python的整数是如何实现的
创始人
2024-03-15 23:16:33
0

本文我们来聊一聊Python的整数,我们知道 Python 的整数是不会溢出的,换句话说,它可以计算无穷大的数,只要你的内存足够,它就能计算。

而 C 显然没有这个特征,C 里面能表示的整数范围是有限的。但问题是,Python 底层又是 C 实现的,那么它是怎么做到整数不溢出的呢?既然想知道答案,那么看一下整数在底层是怎么定义的就行了。

整数的底层实现

Python 整数在底层对应的结构体是 PyLongObject,我们看一下具体的定义,这里的源码版本为最新的 3.11。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

// Include/cpython/longintrepr.h

struct _longobject {

    PyObject_VAR_HEAD

    digit ob_digit[1];

};

// Include/pytypedefs.h

typedef struct _longobject PyLongObject;

// 将两者合起来可以看成

typedef struct {

    PyObject_VAR_HEAD

    digit ob_digit[1];

} PyLongObject;

// 如果把这个PyLongObject 更细致的展开一下

typedef struct {

    // 引用计数  

    Py_ssize_t ob_refcnt; 

    // 类型

    struct _typeobject *ob_type; 

    // 维护的元素个数

    Py_ssize_t ob_size;

    // digit 类型的数组,长度为 1 

    digit ob_digit[1]; 

} PyLongObject;

别的先不说,就冲里面的 ob_size 我们就可以思考一番。首先 Python 的整数有大小、但应该没有长度的概念吧,那为什么会有一个 ob_size 呢?

从结构体成员来看,这个 ob_size 指的应该就是数组 ob_digit 的长度,而这个 ob_digit 显然只能是用来维护具体的值了。而数组的长度不同,那么对应的整数占用的内存也不同。

所以答案出来了,整数虽然没有我们生活中的那种长度的概念,但它是个变长对象,因为不同的整数占用的内存可能是不一样的。因此这个 ob_size 指的是底层数组的长度,因为整数对应的值在底层是使用数组来存储的。尽管它没有字符串、列表那种长度的概念,或者说无法对整数使用 len 函数,但它是个变长对象。

那么下面的重点就在这个 ob_digit 数组身上了,我们要从它的身上挖掘信息,看看一个整数是怎么放在这个数组里面的。不过首先我们要搞清楚这个 digit 是什么类型,它的定义同样位于 longintrepr.h 中:

1

2

3

4

5

6

7

8

9

10

11

// PYLONG_BITS_IN_DIGIT是一个宏

// 至于这个宏是做什么的我们先不管

// 总之,如果机器是 64 位的,那么它会被定义为 30

// 机器是 32 位的,则会被定义为 15

#if PYLONG_BITS_IN_DIGIT == 30

typedef uint32_t digit;

// ...

#elif PYLONG_BITS_IN_DIGIT == 15

typedef unsigned short digit;

// ...

#endif

由于现在基本上都是 64 位机器,所以我们只考虑 64 位,显然 PYLONG_BITS_IN_DIGIT 会等于 30。因此 digit 等价于 uint32_t,也就是 unsigned int,所以它是一个无符号 32 位整型。

因此 ob_digit 是一个无符号 32 位整型数组,长度为 1。当然这个数组具体多长则取决于你要存储的整数有多大,不同于 Golang,C 数组的长度不属于类型信息。

虽然定义的时候,声明数组的长度为 1,但你可以把它当成任意长度的数组来用,这是 C 语言中常见的编程技巧。至于长度具体是多少,则取决于你的整数大小。显然整数越大,这个数组就越长,占用的空间也就越大。

搞清楚了 PyLongObject 里面的所有成员,那么下面我们就来分析 ob_digit 是怎么存储整数的,以及 Python 的整数为什么不会溢出。

不过说实话,关于整数不会溢出这个问题,相信很多人已经有答案了。因为底层是使用数组存储的,而数组的长度又没有限制,所以当然不会溢出。

转载自:https://www.weidianyuedu.com

相关内容

热门资讯

AWSECS:访问外部网络时出... 如果您在AWS ECS中部署了应用程序,并且该应用程序需要访问外部网络,但是无法正常访问,可能是因为...
AWSElasticBeans... 在Dockerfile中手动配置nginx反向代理。例如,在Dockerfile中添加以下代码:FR...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...
北信源内网安全管理卸载 北信源内网安全管理是一款网络安全管理软件,主要用于保护内网安全。在日常使用过程中,卸载该软件是一种常...
AWR报告解读 WORKLOAD REPOSITORY PDB report (PDB snapshots) AW...
AWS管理控制台菜单和权限 要在AWS管理控制台中创建菜单和权限,您可以使用AWS Identity and Access Ma...
​ToDesk 远程工具安装及... 目录 前言 ToDesk 优势 ToDesk 下载安装 ToDesk 功能展示 文件传输 设备链接 ...
群晖外网访问终极解决方法:IP... 写在前面的话 受够了群晖的quickconnet的小水管了,急需一个新的解决方法&#x...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
Azure构建流程(Power... 这可能是由于配置错误导致的问题。请检查构建流程任务中的“发布构建制品”步骤,确保正确配置了“Arti...