Python中的短整型数据类型

32

Python根据底层系统架构自动分配整数。不幸的是,我有一个需要完全加载到内存的大型数据集。

那么,有没有办法强制Python只使用2字节来表示某些整数(相当于C++中的“short”)?


2
如果你正在对这个巨大的数据集进行任何形式的操作,你可能会想要使用Numpy,它支持各种数字类型,并且可以高效地对它们的数组进行操作。 - giltay
4
提醒一下:C++ 的 short 类型不一定是 2 字节宽度,这取决于具体的实现。 - user3063349
6个回答

45

不行。但是,您可以在数组中使用短整数:

from array import array
a = array("h") # h = signed short, H = unsigned short

只要该值保留在该数组中,它就将是一个短整型。

比我的回答更好、更完整。 :) - Nick Johnson
那么,只有一个元素的数组('h')和创建一个短整型是否相同? - Arnav
1
@Arnav:不是的。那将是一个PyObject +一个短整数。 - Armin Ronacher

5
你可以使用NumPy的int类型,如np.int8或np.int16。

2
我的名字是NumPy - 带有一个umpy。所有其他数据包都允许我推动你。 - Nic F

5
感谢Armin指出了“array”模块。我还发现了“struct”模块,它可以将C语言风格的结构体打包成字符串:
从文档中可以看到(https://docs.python.org/library/struct.html):
>>> from struct import *
>>> pack('hhl', 1, 2, 3)
'\x00\x01\x00\x02\x00\x00\x00\x03'
>>> unpack('hhl', '\x00\x01\x00\x02\x00\x00\x00\x03')
(1, 2, 3)
>>> calcsize('hhl')
8

3

Armin提供的数组模块可能是最好的选择。还有两个可能的替代方案:

  • 您可以创建自己的扩展模块,以提供所需的数据结构。如果只是像一组短整型这样的东西,那么这很简单。
  • 您可以欺骗并操纵位,以便将一个数字存储在Python int的下半部分中,将另一个数字存储在上半部分中。您需要编写一些实用函数来在数据结构内部进行转换。这很丑陋,但可以实现。

值得注意的是,Python整数对象不是4个字节 - 还有额外的开销。因此,如果您有大量的shorts,则可以通过某种方式使用C short来每个数字节省超过两个字节(例如使用数组模块)。

我之前必须在内存中保存大量的整数,使用整数键和值的字典过大(我记得为该数据结构提供了1GB)。我切换到使用IIBTree(来自ZODB),并设法适应它。(IIBTree中的整数是真正的C int,而不是Python整数,并且当数字大于32位时,我会自动切换到IOBTree)。


我能在不安装Zope的情况下使用IIBTree吗?我从哪里获取它?IOBTree是什么? - Greg
只需安装ZODB(http://pypi.python.org/pypi/ZODB3/3.8.0)。IOBTree是具有整数键(I)和对象值(O)的BTree。 - Tony Meyer

1
您还可以使用单个大整数存储多个任意大小的整数。
例如,在64位x86系统上,python3中,1024位占用164字节的存储空间。这意味着平均每个字节可以存储约6.24位。如果您使用更大的整数,则可以获得更高的位存储密度。例如,使用2 ** 20位宽的整数可获得约7.50位每字节的存储密度。
显然,您需要一些包装器逻辑来访问存储在较大整数中的短数字,这很容易实现。
使用此方法的一个问题是由于大整数操作的使用,数据访问将放慢速度。
如果您一次访问一大批连续存储的整数以最小化对大整数的访问,则长整数的较慢访问不会成为问题。
我想使用numpy会更容易一些。
>>> a = 2**1024
>>> sys.getsizeof(a)
164
>>> 1024/164
6.2439024390243905

>>> a = 2**(2**20)
>>> sys.getsizeof(a)
139836
>>> 2**20 / 139836
7.49861266054521

1

在Python中使用bytearray,它基本上是C语言无符号字符数组的实现方式,比使用大整数更好。操作字节数组没有额外开销,并且与大整数相比,它具有更少的存储开销。使用bytearrays可以获得每字节7.99+位的存储密度。

>>> import sys
>>> a = bytearray(2**32)
>>> sys.getsizeof(a)
4294967353
>>> 8 * 2**32 / 4294967353
7.999999893829228

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接