在Python中构建二进制表示的二进制数字列表
我有一个很大的由0和1组成的列表,这些数字在Python中默认是以整数的形式表示的,代码是:[randint(0, 1) for i in range(50*98)]
我想优化这个代码,让它占用更少的内存。显而易见的方法是用1个比特位来表示每一个数字。
在Python中,有没有办法创建一个真正的二进制数字列表呢?
问候,
布鲁诺
编辑:谢谢大家。
从大家的回答中我了解到,Python默认并不支持这个功能,所以我找到一个库(在Macports上安装在OSX上,这样省了我不少麻烦),它可以进行位操作:python-bitstring
5 个回答
这叫做位向量,或者说位图。你可以试试这个,比如 BitVector。如果你想自己实现一个,你需要用数字对象,而不是列表,并且要用位运算来切换位,比如:
bitmap = 0
bit = (1 << 24)
bitmap |= bit # enable bit
bitmap &= ~bit # disable bit
正如delnan在评论中提到的,如果你想要逐位相等的内存使用情况,那么你就不能使用真正的二进制数字。
整数(或者长整型)当然是真正的二进制数字,因为你可以通过位运算符来操作单独的位(不过这在类中可能会被隐藏起来)。另外,long
对象可以变得非常大,也就是说你可以用它们来模拟任意大的位集合。在Python中这样做可能不会很快,但也不算太难,是个不错的开始。
使用你上面提到的二进制生成方法,你可以这样做:
reduce(
lambda (a, p), b: (b << p | a, p + 1),
(random.randint(0, 1) for i in range(50*98)),
(0, 0)
)[0]
当然,random
支持任意大的上限,所以你可以这样做:
r = random.randint(0, 2**(50*98))
这并不完全相同,因为这里的每个二进制位并不是独立的,和你单独生成每个数字时的独立性不同。不过,了解你的伪随机数生成器(pRNG)是如何工作的,它们在另一种情况下也并不是真正独立的。如果这对你来说很重要,你可能根本不应该使用random
模块,而是使用硬件随机数生成器(RNG)。
这个内容使用了一个叫做 bitstring 的模块,并从你的列表中创建了一个 BitArray
对象:
from bitstring import BitArray
b = BitArray([randint(0, 1) for i in range(50*98)])
在内部,这个对象现在以字节的形式存储,所以占用的内存会少很多。你可以像平常一样对它进行切片、索引、检查和设置位等操作,还有一些额外的方法,比如 set
、all
和 any
,可以用来修改这些位。
如果你想把数据以二进制字符串的形式取出来,只需使用 b.bin
,而如果想要获取打包成字节的数据,可以使用 b.tobytes()
,这个方法会把数据填充到字节边界。