58 Stimmen

Verfügt Python über einen Bitfeldtyp?

Ich brauche eine kompakte Darstellung eines Arrays von Booleschen, hat Python eine eingebaute Bitfeld-Typ oder muss ich eine alternative Lösung zu finden?

53voto

nealmcb Punkte 10705

Wenn Sie hauptsächlich Ihre Bitfelder benennen und leicht manipulieren wollen, z.B. um mit Flags zu arbeiten, die als einzelne Bits in einem Kommunikationsprotokoll dargestellt werden, dann können Sie die Standardfunktionen Struktur und Vereinigung von ctypes wie beschrieben unter Wie deklariere ich ordnungsgemäß eine ctype-Struktur + Union in Python? - Stapel-Überlauf

Um beispielsweise mit den 4 niedrigstwertigen Bits eines Bytes einzeln zu arbeiten, benennen Sie sie einfach von der niedrigsten zur höchsten Wertigkeit in einer LittleEndianStructure. Sie verwenden eine Union, um auf dieselben Daten wie ein Byte oder int zuzugreifen, so dass Sie die Daten in das Kommunikationsprotokoll hinein oder aus ihm heraus verschieben können. In diesem Fall geschieht dies über die flags.asbyte Feld:

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 beginnend mit dem höchstwertigen gedruckt habe, was beim Drucken natürlicher erscheint) sind 1, 1, 0, 0, d.h. 0xc in binärer Form.

33voto

Alex Coventry Punkte 64405

Bitarray war die beste Antwort, die ich gefunden habe, als ich kürzlich ein ähnliches Bedürfnis hatte. Es ist eine C-Erweiterung (so viel schneller als BitVector, die reine Python ist) und speichert seine Daten in einem tatsächlichen Bitfeld (so ist es achtmal effizienter Speicher als ein Numpy boolesche Array, die ein Byte pro Element zu verwenden scheint).

16voto

Scott Griffiths Punkte 20629

Sie sollten einen Blick auf die Bitstring Modul, das kürzlich die Version 2.0 erreicht hat. Die binären Daten werden kompakt als Byte-Array gespeichert und können leicht erstellt, geändert und analysiert werden.

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

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 sie dann mit einfachen Funktionen oder der Slice-Notation analysieren und verändern - ohne sich um Bitmasken usw. kümmern zu müssen.

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 der Bitposition, so dass man es wie eine Datei oder einen Stream behandeln kann, wenn das für Sie nützlich ist. Eigenschaften werden verwendet, um verschiedene Interpretationen der Bitdaten zu ermöglichen.

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

Außerdem gibt es Unterstützung für die standardmäßigen bitweisen Binäroperatoren, Packen, Entpacken, Endianness und mehr. Die neueste Version ist für Python 2.7 und 3.x, und obwohl es reines Python ist, ist es in Bezug auf Speicher und Geschwindigkeit recht gut optimiert.

10voto

MattG Punkte 1312

Stellen Sie jeden Ihrer Werte als eine Potenz von zwei dar:

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

Dann wird ein Wert auf true gesetzt:

table = table | testB

Um einen Wert falsch zu setzen:

table = table & (~testC)

Zum Testen eines Wertes:

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

Informieren Sie sich über die Hexadezimaldarstellung, wenn Ihnen das nicht einleuchtet. Dies ist im Grunde die Art und Weise, wie Sie Ihre booleschen Flags auch in einer eingebetteten C-Anwendung im Auge behalten (wenn Sie nur begrenzten Speicher haben).

7voto

S.Lott Punkte 371691

Ich verwende die binären bitweisen Operatoren !, &, |, ^, >> und <<. Sie funktionieren sehr gut und sind direkt in dem zugrunde liegenden C implementiert, das normalerweise direkt auf der zugrunde liegenden Hardware liegt.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X