Question

J'ai besoin d'une représentation compacte d'un tableau de booléens. Python a-t-il un type de champ binaire intégré ou devrai-je trouver une autre solution?

Était-ce utile?

La solution

Bitarray a été la meilleure réponse que j'ai trouvée lorsque 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 (elle consomme huit fois plus de mémoire qu'un tableau booléen numpy, qui semble utiliser un octet par élément.)

Autres conseils

Si vous souhaitez principalement pouvoir nommer vos champs de bits et les manipuler facilement, par exemple, pour utiliser des indicateurs représentés sous la forme de bits uniques dans un protocole de communication, vous pouvez utiliser les fonctions standard Structure et Union de types , comme décrit à Comment déclarer correctement un ctype 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 flags.asbyte champ:

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.

Vous devriez jeter un coup d'oeil au module bitstring , qui vient de passer à 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 BitString des objets à partir de binaires, octaux, hexadécimaux, entiers (gros ou petits endians), chaînes, octets, flottants, 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, qui vous permet de 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, les opérateurs binaires standard, l’emballage, le déballage, l’endianness et plus encore sont pris en charge. La dernière version concerne les versions 2.7 et 3.x de Python. Bien que purement Python, elle est relativement bien optimisée en termes de mémoire et de vitesse.

J'utilise les opérateurs binaires binaires!, & amp ;, |, ^, > > ;, 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.

Représentez chacune de vos valeurs par une puissance de deux:

testA = 2**0
testB = 2**1
testC = 2**3

Ensuite, pour définir une valeur vraie:

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 trace de vos drapeaux booléens dans une application C intégrée (si vous avez limité la mémoire).

Le package BitVector peut être ce dont vous avez besoin. Il n’est pas intégré à mon installation python, mais facile à localiser sur le site python.

https://pypi.python.org/pypi/BitVector pour la version actuelle .

NumPy a un module interface de tableau 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 du module de tableau .

De plus, le module ctypes contient le champs de bits , 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 des insertions / extraits de champs de bits dans de longs 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 possible en pur python mais beaucoup plus rapide en C.

Pour les bits essentiellement consécutifs, il existe le https://pypi.org/project/range_set/ module compatible avec les API de la version set intégrée de Python. Comme son nom l'indique, il stocke les bits sous forme de paires début / fin.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top