J'ai besoin d'une représentation compacte d'un tableau de booléens. Python a-t-il un type de champ de bits intégré ou devrai-je trouver une autre solution?
Bitarray était la meilleure réponse que j'ai trouvée, quand j'ai eu récemment un besoin similaire. C'est une extension C (beaucoup plus rapide que BitVector, qui est du pur python) et stocke ses données dans un champ de bits réel (donc huit fois plus efficace en mémoire qu'un tableau booléen numpy, qui semble utiliser un octet par élément.)
Si vous souhaitez principalement pouvoir nommer vos champs de bits et les manipuler facilement, par exemple, Pour utiliser des indicateurs représentés sous forme de bits uniques dans un protocole de communication, vous pouvez utiliser les fonctions standard Structure et Union de ctypes , comme décrit à Comment déclarer correctement un type de structure + Union en Python? - Débordement de pile
Par exemple, pour utiliser les 4 bits les moins significatifs d'un octet individuellement, il suffit de les nommer du moins au plus significatif dans une structure LittleEndian. Vous utilisez une union pour fournir l'accès aux mêmes données sous la forme d'un octet ou d'un entier afin que vous puissiez déplacer les données dans ou en dehors du protocole de communication. Dans ce cas, cela se fait via le champ 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)
Les quatre bits (que j’ai imprimés ici en commençant par le plus significatif, ce qui semble plus naturel lors de l’impression) sont 1, 1, 0, 0, c’est-à-dire 0xc en binaire.
Jetez un coup d'œil au module bitstring , qui a récemment atteint la version 2.0 . Les données binaires sont stockées de manière compacte sous forme de tableau d'octets et peuvent être facilement créées, modifiées et analysées.
Vous pouvez créer des objets BitString
à partir de binaires, octaux, hexadécimaux, entiers (gros ou petits endians), chaînes, octets, floats, fichiers, etc.
a = BitString('0xed44')
b = BitString('0b11010010')
c = BitString(int=100, length=14)
d = BitString('uintle:16=55, 0b110, 0o34')
e = BitString(bytes='hello')
f = pack('<2H, bin:3', 5, 17, '001')
Vous pouvez ensuite les analyser et les modifier avec des fonctions simples ou une notation par tranches - vous n'avez pas à vous soucier des masques de bits, etc.
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] = 'uint:11=33, int:9=-1'
Il existe également un concept de position de bit, afin que vous puissiez le traiter comme un fichier ou un flux, si cela vous est utile. Les propriétés sont utilisées pour donner différentes interprétations des données de bits.
w = g.read(10).uint
x, y, z = g.readlist('int:4, int:4, hex:32')
if g.peek(8) == '0x00':
g.pos += 10
De plus, il prend en charge les opérateurs binaires bit à bit standard, l’emballage, le déballage, l’endianisme et plus encore. La dernière version concerne les versions 2.7 et 3.x de Python. Bien que ce soit du pur Python, il est relativement bien optimisé en termes de mémoire et de vitesse.
Représentez chacune de vos valeurs comme un pouvoir de deux:
testA = 2**0
testB = 2**1
testC = 2**3
Ensuite, pour définir une valeur true:
table = table | testB
Pour définir une valeur false:
table = table & (~testC)
Pour tester une valeur:
bitfield_length = 0xff
if ((table & testB & bitfield_length) != 0):
print "Field B set"
Creusez un peu plus dans la représentation hexadécimale si cela n’a aucun sens pour vous. C’est essentiellement ainsi que vous gardez une trace de vos drapeaux booléens dans une application C intégrée (si vous avez limité la mémoire).
J'utilise les opérateurs binaires binaires!, &, |, ^, >> et <<. Ils fonctionnent vraiment bien et sont implémentés directement dans le C sous-jacent, qui est généralement directement sur le matériel sous-jacent.
Le package BitVector peut être ce dont vous avez besoin. Cela ne fait pas partie de mon installation python, mais est facile à localiser sur le site python.
https://pypi.python.org/pypi/BitVector pour la version actuelle.
NumPy a un module d'interface array que vous pouvez utiliser pour créer un champ de bits.
Si votre champ de bits est court, vous pouvez probablement utiliser le module struct . Sinon, je recommanderais une sorte de wrapper autour de le module de tableau .
De plus, le module ctypes contient bitfields , mais je ne l'ai jamais utilisé moi-même. Caveat emptor.
Si vous souhaitez utiliser ints (ou long ints) pour représenter des tableaux de bools (ou des ensembles d'entiers), consultez http://sourceforge.net/projects/pybitop/files/
Il fournit l'insertion/extrait de champs de bits dans de longues ints; trouver le bit '1' le plus significatif ou le moins significatif; compter tous les 1; inversion de bits; des trucs comme celui qui est tout possible en python pur mais beaucoup plus rapide en C.
Le module https://pypi.org/project/range_set/ est un API compatible avec la variable set
de Python. Comme son nom l'indique, il stocke les bits sous forme de paires début/fin.