Python有位字段类型吗?

57 投票
12 回答
78943 浏览
提问于 2025-04-11 09:29

我需要一种紧凑的方式来表示一个布尔值数组,Python有没有内置的位字段类型,还是我需要找其他解决办法?

12 个回答

16

你可以看看这个叫做 bitstring 的模块,它最近更新到了4.0版本。这个模块可以把二进制数据紧凑地存储为字节数组,使用起来非常方便,可以轻松创建、修改和分析数据。

你可以从二进制、八进制、十六进制、整数(无论是大端还是小端)、字符串、字节、浮点数、文件等等来创建bitstring对象。

from bitstring import BitArray, BitStream
a = BitArray('0xed44')
b = BitArray('0b11010010')
c = BitArray(int=100, length=14)
d = BitArray('uintle:16=55, 0b110, 0o34')
e = BitArray(bytes='hello')
f = pack('<2H, bin:3', 5, 17, '001') 

然后你可以用简单的函数或者切片语法来分析和修改这些对象,不用担心位掩码之类的复杂问题。

a.prepend('0b110')
if '0b11' in b:
    c.reverse()
g = a.join([b, d, e])
g.replace('0b101', '0x3400ee1')
if g[14]:
    del g[14:17]
else:
    g[55:58] = 'uint11=33, int9=-1'

这个模块还有一个位位置的概念,这样你就可以像处理文件或流一样来使用它,如果这样对你有帮助的话。它的属性可以用来给位数据提供不同的解释。

g = BitStream(g)
w = g.read(10).uint
x, y, z = g.readlist('int4, int4, hex32')
if g.peek(8) == '0x00':
    g.pos += 10

此外,它还支持标准的位运算符、打包、解包、字节序等功能。最新版本适用于Python 3.7及以上,并且在内存和速度方面做了合理的优化。

50

如果你主要想给你的位域命名,并且方便地操作它们,比如在通信协议中处理以单个位表示的标志,那么你可以使用ctypes的标准结构和联合体功能,具体可以参考如何在Python中正确声明ctype结构和联合体? - Stack Overflow

举个例子,如果你想单独处理一个字节的4个最低有效位,只需在一个LittleEndianStructure中按从低到高的顺序给它们命名。你可以使用联合体来以字节或整数的形式访问相同的数据,这样就可以在通信协议中进出这些数据。在这个例子中,通过flags.asbyte字段来实现:

import ctypes
c_uint8 = ctypes.c_uint8

class Flags_bits(ctypes.LittleEndianStructure):
    _fields_ = [
            ("logout", c_uint8, 1),
            ("userswitch", c_uint8, 1),
            ("suspend", c_uint8, 1),
            ("idle", c_uint8, 1),
        ]

class Flags(ctypes.Union):
    _fields_ = [("b", Flags_bits),
                ("asbyte", c_uint8)]

flags = Flags()
flags.asbyte = 0xc

print(flags.b.idle)
print(flags.b.suspend)
print(flags.b.userswitch)
print(flags.b.logout)

这四个位(我这里是从最高有效位开始打印的,这样看起来更自然)是1, 1, 0, 0,也就是二进制的0xc。

32

我最近遇到过类似的需求,发现Bitarray是最好的选择。它是一个C语言扩展,所以比纯Python写的BitVector要快很多。而且它的数据存储在一个真正的位域中,这样在内存使用上比numpy的布尔数组要高效八倍,因为后者每个元素看起来都要用一个字节。

撰写回答