2008-09-27 10 views
39

Ich brauche eine kompakte Darstellung eines Booleschen Arrays, hat Python einen eingebauten Bitfeldtyp oder muss ich eine alternative Lösung finden?Hat Python einen Bitfeldtyp?

+0

Für Fälle, in denen der Begriff mehrdeutig ist, nehme ich an, dass Sie die Arten von Funktionen in C-Bit-Feldern oder wie hier beschrieben möchten? http://en.wikipedia.org/wiki/Bit_field – nealmcb

Antwort

26

Bitarray war die beste Antwort, die ich fand, als ich kürzlich eine ähnliche Notwendigkeit hatte. Es ist eine C-Erweiterung (so viel schneller als BitVector, die pure Python ist) und speichert seine Daten in einem tatsächlichen Bitfeld (es ist also achtmal mehr Speicher effizienter als ein boolesch Array numby, die ein Byte pro Element zu verwenden scheint.)

+0

Ist 'BitArray' für die Installation unter Windows verfügbar? – IAbstract

+0

Es sieht so aus, als ob "BitArray" für die Installation unter Linux verfügbar ist, aber nichts auf der Seite schlägt eine PIP-Installation für Windows vor. Bummer ... – IAbstract

4

NumPy hat ein array interface Modul, das Sie verwenden können, um ein Bitfeld zu erstellen.

+0

Das eingebaute [array] (http://docs.python.org/library/array.html) Modul ist auch ausreichend für ein Bit-Array und mehr portabel (über Python impls) als NumPy. – gsnedders

5

Das BitVector-Paket ist möglicherweise das, was Sie brauchen. Es ist nicht in meine Python-Installation integriert, aber auf der Python-Site leicht zu finden.

https://pypi.python.org/pypi/BitVector für die aktuelle Version.

2

Wenn Ihr Bitfeld kurz ist, können Sie wahrscheinlich the struct module verwenden. Ansonsten würde ich eine Art Wrapper um the array module empfehlen.

Auch das Ctypes-Modul enthält bitfields, aber ich habe es nie selbst verwendet. Caveat emptor.

+1

Aber es scheint, dass das Struktur-Modul jedes Bit als ein Char oder Byte darstellt, so dass es nicht wirklich Bitfelder behandelt, wie normalerweise definiert (wo Bits im Speicher dicht gepackt sind). – nealmcb

6

Ich benutze die binären bitweisen Operatoren!, &, |, ^, >>, und < <. Sie arbeiten sehr gut und werden direkt in das zugrunde liegende C implementiert, das normalerweise direkt auf der zugrunde liegenden Hardware liegt.

6

Repräsentieren jedes Ihrer Werte als Zweierpotenz:

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

Dann wahren Wert zu setzen:

table = table | testB 

falschen Wert zu setzen:

table = table & (~testC) 

zu Test auf einen Wert:

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

Graben Sie etwas tiefer in die hexadezimale Darstellung, wenn dies für Sie keinen Sinn ergibt. Dies ist im Grunde, wie Sie Ihre booleschen Flags auch in einer eingebetteten C-Anwendung verfolgen (wenn Sie Speicher begrenzt haben).

+0

Große Antwort. Ich mag und mag nicht, dass es zur gleichen Zeit manuell ist. Es gibt jedoch keine logischere Möglichkeit, eine Bitfeldklasse manuell zu erstellen. – RobotHumans

11

Sie sollten sich das Modul bitstring ansehen, das kürzlich die Version 2.0 erreicht hat. Die Binärdaten sind kompakt als Byte-Array gespeichert und können einfach erstellt, modifiziert und analysiert werden.

Sie können BitString Objekte aus Binär, Oktal, Hex, Ganzzahlen (Big oder Little Endian), Strings, Bytes, Floats, Dateien und mehr erstellen.

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') 

Sie können dann analysieren und sie mit einfachen Funktionen oder Slice-Notation ändern - keine Notwendigkeit, über Bitmasken sorgen usw.

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' 

Es gibt auch ein Konzept einer Bit-Position, so dass Sie kann es wie eine Datei oder einen Stream behandeln, wenn es dir nützlich ist. Eigenschaften werden verwendet, um unterschiedliche Interpretationen der Bitdaten zu geben.

w = g.read(10).uint 
x, y, z = g.readlist('int:4, int:4, hex:32') 
if g.peek(8) == '0x00': 
    g.pos += 10 

plus gibt es Unterstützung für die Standard-bitweise binäre Operatoren, Verpackung, Auspacken, endianness und vieles mehr. Die neueste Version ist für Python 2.7 und 3.x, und obwohl es pures Python ist, ist es in Bezug auf Speicher und Geschwindigkeit relativ gut optimiert.

+1

Ich mag das! Ein bisschen intuitiver als Bitarray für mich. Vielen Dank! – weronika

+0

der Link ist tot –

1

Wenn Sie Ints verwenden (oder lange Ints) als Arrays von bools (oder als Mengen von ganzen Zahlen) zu repräsentieren, einen Blick auf http://sourceforge.net/projects/pybitop/files/

Es bietet insert/Extrakt aus bitfields in langen Ints; Finden des höchstwertigen oder niedrigstwertigen "1" -Bits; Zählen aller 1en; Bit-Umkehrung; Sachen wie das, was in Python alles möglich ist, aber viel schneller in C.

29

Wenn Sie hauptsächlich in der Lage sein möchten, Ihre Bitfelder zu benennen und sie leicht zu manipulieren, z. Um mit Flags zu arbeiten, die als einzelne Bits in einem Kommunikationsprotokoll dargestellt werden, können Sie die Standardstruktur- und Union-Merkmale von verwenden, wie zum Beispiel beschrieben, um mit den 4 niedrigstwertigen Bits eines Bytes einzeln zu arbeiten, wie bei How Do I Properly Declare a ctype Structure + Union in Python? - Stack Overflow beschrieben Benennen Sie sie in einer LittleEndianStructure am wenigsten oder am signifikantesten. Sie verwenden eine Union, um Zugriff auf die gleichen Daten wie ein Byte oder einen Int zu ermöglichen, damit Sie die Daten in das Kommunikationsprotokoll ein- oder auslagern können. In diesem Fall, dass über das flags.asbyte Feld getan:

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) 

Die vier Bits (die ich hier gedruckt habe mit den bedeutendsten Ausgang, die natürlichere scheint beim Drucken) sind 1, 1, 0, 0, dh 0xc binär.