为什么大小为2⁶³36字节,但2⁶³-1只有24字节?

时间:2018-03-07 13:58:40

标签: python python-2.7 cpython python-internals

Python中的所有内容都是一个对象。所以Python中int的大小会比平时大。

>>> sys.getsizeof(int())
24

好的,但为什么2⁶³需要多12个字节才比2⁶³ - 1而不只是一个呢?

>>> sys.getsizeof(2**63)
36
>>> sys.getsizeof(2**62)
24

我认为2⁶³是一个长2⁶³-1个整数,但为什么会有12个字节的差异?

不再直观,我尝试了其他一些事情:

>>> a = 2**63
>>> a -= 2**62
>>> sys.getsizeof(a)
36

a仍然存储为long,即使它现在可以在int中。所以这并不奇怪。但是:

>>> a -= (2**63 - 1)
>>> a = 2**63
>>> a -= (2**63 - 1)
>>> a
1L
>>> sys.getsizeof(a)
28

新尺寸。

>>> a = 2**63
>>> a -= 2**63
>>> a
0L
>>> sys.getsizeof(a)
24

返回24个字节,但仍然很长。

我得到的最后一件事:

>>> sys.getsizeof(long())
24

问题:

在这些情况下,内存存储如何工作?

子的问题:

为什么有12个字节的间隙来添加我们的直觉告诉我们只有1位?

为什么int()long()为24个字节,但long(1)已经是28个字节且int(2⁶²)

注意:Python 3.X的工作方式略有不同,但并不直观。在这里,我专注于Python 2.7;我没有测试以前的版本。

2 个答案:

答案 0 :(得分:62)

  

为什么它为2⁶³增加12个字节,相比之下2⁶³-1而不仅仅是1个?

LP64系统 1 上,Python 2 int consists of正好有三个指针大小的部分:

  • 类型指针
  • 参考计数
  • 实际值,C long int

这总共是24个字节。另一方面,Python long consists of

  • 类型指针
  • 参考计数
  • 数字计数,指针大小的整数
  • 值数字的内联数组,每个数组保存30位值,但以32位为单位存储(其中一个未使用的位在加法和减法期间用于efficient carry/borrow

2 ** 63需要64位存储,因此它适合三个30位数字。由于每个数字的宽度为4个字节,因此整个Python long将需要24 + 3 * 4 = 36个字节。

换句话说,差异来自于long必须单独存储数字的大小(8个额外字节),并且差异来自于存储值的空间效率稍差(12个字节用于存储数字) 2 ** 63)。包括大小,long中的值2 ** 63占用20个字节。将其与简单int任何值占用的8个字节进行比较,可以得出观察到的12字节差异。

值得注意的是,Python 3只有一个整数类型,称为int,它是可变宽度的,并且与Python 2 long的实现方式相同。

<小时/> 1 64位Windows的不同之处在于它保留了32位long int,大概是为了与使用charshortlong的大量旧代码的源代码兼容作为8位,16位和32位值的“方便”别名,恰好适用于16位和32位系统。要在x86-64 Windows上获得实际的64位类型,必须使用__int64或(在较新的编译器版本上)long longint64_t。由于Python 2内部依赖于Python int在不同位置适合C long,sys.maxint仍然是2**31-1,即使在64位Windows上也是如此。这个怪癖也在Python 3中修复,它没有 maxint 的概念。

答案 1 :(得分:5)

虽然我没有在文档中找到它,但这是我的解释。

当值超过可以存储在int中的值时,Python 2会隐式地将Picture 3提升为int。新类型(long)的大小是long的默认大小,即32。从现在开始,变量的大小将由其值决定,该值可以上升,下来。

long

正如您所看到的,类型在from sys import getsizeof as size a = 1 n = 32 # going up for i in range(10): if not i: print 'a = %100s%13s%4s' % (str(a), type(a), size(a)) else: print 'a = %100s%14s%3s' % (str(a), type(a), size(a)) a <<= n # going down for i in range(11): print 'a = %100s%14s%3s' % (str(a), type(a), size(a)) a >>= n a = 1 <type 'int'> 24 a = 4294967296 <type 'long'> 32 a = 18446744073709551616 <type 'long'> 36 a = 79228162514264337593543950336 <type 'long'> 40 a = 340282366920938463463374607431768211456 <type 'long'> 44 a = 1461501637330902918203684832716283019655932542976 <type 'long'> 48 a = 6277101735386680763835789423207666416102355444464034512896 <type 'long'> 52 a = 26959946667150639794667015087019630673637144422540572481103610249216 <type 'long'> 56 a = 115792089237316195423570985008687907853269984665640564039457584007913129639936 <type 'long'> 60 a = 497323236409786642155382248146820840100456150797347717440463976893159497012533375533056 <type 'long'> 64 a = 2135987035920910082395021706169552114602704522356652769947041607822219725780640550022962086936576 <type 'long'> 68 a = 497323236409786642155382248146820840100456150797347717440463976893159497012533375533056 <type 'long'> 64 a = 115792089237316195423570985008687907853269984665640564039457584007913129639936 <type 'long'> 60 a = 26959946667150639794667015087019630673637144422540572481103610249216 <type 'long'> 56 a = 6277101735386680763835789423207666416102355444464034512896 <type 'long'> 52 a = 1461501637330902918203684832716283019655932542976 <type 'long'> 48 a = 340282366920938463463374607431768211456 <type 'long'> 44 a = 79228162514264337593543950336 <type 'long'> 40 a = 18446744073709551616 <type 'long'> 36 a = 4294967296 <type 'long'> 32 a = 1 <type 'long'> 28 开始变得太大之后保持long,初始大小为32,但是大小随着值的变化而变化(可以更高或更低) [或者相当,显然]到32)

因此,要回答您的问题,int的基本大小为24,int的基本大小为28,而long也有用于保存大值的空间(以4开头) bytes - 因此long为32个字节,但可以根据值上下移动

至于你的子问题,为新数字创建一个唯一类型(具有唯一大小)是不可能的,因此Python有&#34;子类&#34; long类型的long类型,处理一系列数字,因此,一旦超过旧long的限制,您必须使用较新的,因为它也会占用更大的数字,因此它具有几个字节。