我需要一个布尔数组的紧凑表示方式,Python中是否有内置的位域类型或者我需要寻找一种替代方案?
我需要一个布尔数组的紧凑表示方式,Python中是否有内置的位域类型或者我需要寻找一种替代方案?
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)
Bitarray是我最近寻找类似需求时找到的最佳解决方案。它是一个C扩展程序(比纯python的BitVector快得多),并且将其数据存储在实际的位域中(因此它比numpy布尔数组更节省8倍的内存,后者似乎每个元素使用一个字节)。
BitArray
在 Windows 上可安装吗? - IAbstractBitArray
在 Linux 上可以轻松安装,但页面上没有任何关于 Windows 的 PIP 安装的提示。有点遗憾... - IAbstractfrom 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
bitstring
模块的作者。 - undefined将您的每个值表示为2的幂:
testA = 2**0
testB = 2**1
testC = 2**3
然后设置值为真:
table = table | testB
设置一个值为false:
table = table & (~testC)
测试某个值:
bitfield_length = 0xff
if ((table & testB & bitfield_length) != 0):
print "Field B set"
我使用二进制位运算符!、&、|、^、>>和<<。它们工作得非常好,直接在底层的C语言中实现,通常直接在底层硬件上实现。
如果你想使用整数(或长整数)表示布尔数组(或整数集合),可以看一下http://sourceforge.net/projects/pybitop/files/。
它提供了将位域插入/提取到长整数中;查找最高位或最低位的“1”位;计算所有“1”的数量;位反转等功能,这些在纯Python中都是可能的,但在C中速度更快。
我需要一个没有外部依赖的最小化、内存高效的位域,这就是它:
import math
class Bitfield:
def __init__(self, size):
self.bytes = bytearray(math.ceil(size / 8))
def __getitem__(self, idx):
return self.bytes[idx // 8] >> (idx % 8) & 1
def __setitem__(self, idx, value):
mask = 1 << (idx % 8)
if value:
self.bytes[idx // 8] |= mask
else:
self.bytes[idx // 8] &= ~mask
使用:
# if size is not a multiple of 8, actual size will be the next multiple of 8
bf = Bitfield(1000)
bf[432] # 0
bf[432] = 1
bf[432] # 1