54 votes

Python possède-t-il un type bitfield ?

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

0 votes

Pour les cas où le terme est ambigu, j'en déduis que vous voulez les types de fonctionnalités disponibles dans les champs de bits C, ou telles que décrites ici ? fr.wikipedia.org/wiki/Bit_field

45voto

nealmcb Points 1223

Si vous souhaitez principalement être en mesure de nommer vos champs de bits et de les manipuler facilement, par exemple pour travailler avec des drapeaux représentés sous forme de bits uniques dans un protocole de communication, vous pouvez utiliser les fonctions standard Structure et Union de l'interface utilisateur. ctypes comme décrit à Comment déclarer correctement une structure ctype + Union en Python ? - Stack Overflow

Par exemple, pour travailler individuellement avec les 4 bits les moins significatifs d'un octet, il suffit de les nommer du moins au plus significatif dans une LittleEndianStructure. Vous utilisez une union pour fournir un accès aux mêmes données qu'un octet ou un int afin de pouvoir déplacer les données dans ou hors du protocole de communication. Dans ce cas, cela se fait par le biais de la fonction 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 à l'impression) sont 1, 1, 0, 0, c'est-à-dire 0xc en binaire.

32voto

Alex Coventry Points 11090

Réseau binaire 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 (donc beaucoup plus rapide que BitVector, qui est purement python) et stocke ses données dans un champ de bits réel (donc c'est huit fois plus efficace en mémoire qu'un tableau booléen numpy, qui semble utiliser un octet par élément).

1 votes

Est BitArray disponible pour l'installation sur Windows ?

1 votes

On dirait que BitArray est facilement disponible pour une installation sur Linux mais rien sur la page ne suggère une installation PIP pour Windows. C'est dommage...

0 votes

Ce bon vieux Christoph Gohlke, je dis Construction d'un réseau de bits sous Windows :) Le site peut dire "Unofficial Windows Binaries for Python Extension Packages" mais j'ai utilisé des tas de paquets et je n'ai jamais eu de problème.

16voto

Scott Griffiths Points 8867

Vous devriez jeter un coup d'œil à la chaîne de bits 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 BitString d'objets binaires, octaux, hexagonaux, entiers (big ou little endian), chaînes de caractères, octets, flottants, fichiers et autres.

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 à l'aide de fonctions simples ou de la notation en tranches - sans avoir à 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 binaire, de sorte que vous pouvez 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 binaires.

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 standard, l'empaquetage, le dépaquetage, l'endiannage et bien plus encore. La dernière version est compatible avec Python 2.6 à 3.1, et bien qu'il s'agisse de Python pur, il est raisonnablement bien optimisé en termes de mémoire et de vitesse.

1 votes

J'aime bien celui-là ! Un peu plus intuitif que bitarray pour moi. Merci !

9voto

MattG Points 1127

Représentez chacune de vos valeurs comme 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 fausse :

table = table & (~testC)

Pour tester une valeur :

bitfield_length = 0xff
if ((table & testB & bitfield_length) != 0):
    print "Field B set"

Creusez un peu plus loin dans la représentation hexadécimale si cela n'a pas de sens pour vous. C'est aussi la façon dont vous gardez la trace de vos drapeaux booléens dans une application C embarquée (si vous avez une mémoire limitée).

0 votes

Excellente réponse. J'aime et je n'aime pas que ce soit manuel en même temps. Il n'y a pas de manière plus logique de construire manuellement une classe de champs de bits.

5voto

JasonTrue Points 13615

Le paquet BitVector est peut-être ce dont vous avez besoin. Il n'est pas intégré à mon installation python, mais il est facile à trouver sur le site python.

http://pypi.python.org/pypi/BitVector/1.5.1 est la version actuelle à ce jour.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X