在Python中构建二进制表示的二进制数字列表

3 投票
5 回答
5150 浏览
提问于 2025-04-17 01:28

我有一个很大的由0和1组成的列表,这些数字在Python中默认是以整数的形式表示的,代码是:[randint(0, 1) for i in range(50*98)]

我想优化这个代码,让它占用更少的内存。显而易见的方法是用1个比特位来表示每一个数字。

在Python中,有没有办法创建一个真正的二进制数字列表呢?

问候,
布鲁诺

编辑:谢谢大家。
从大家的回答中我了解到,Python默认并不支持这个功能,所以我找到一个库(在Macports上安装在OSX上,这样省了我不少麻烦),它可以进行位操作:python-bitstring

5 个回答

1

这叫做位向量,或者说位图。你可以试试这个,比如 BitVector。如果你想自己实现一个,你需要用数字对象,而不是列表,并且要用位运算来切换位,比如:

 bitmap = 0
 bit = (1 << 24)
 bitmap |= bit  # enable bit
 bitmap &= ~bit # disable bit
2

正如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)。

4

这个内容使用了一个叫做 bitstring 的模块,并从你的列表中创建了一个 BitArray 对象:

from bitstring import BitArray
b = BitArray([randint(0, 1) for i in range(50*98)])

在内部,这个对象现在以字节的形式存储,所以占用的内存会少很多。你可以像平常一样对它进行切片、索引、检查和设置位等操作,还有一些额外的方法,比如 setallany,可以用来修改这些位。

如果你想把数据以二进制字符串的形式取出来,只需使用 b.bin,而如果想要获取打包成字节的数据,可以使用 b.tobytes(),这个方法会把数据填充到字节边界。

撰写回答