Ich brauche eine kompakte Darstellung eines Arrays von Booleschen, hat Python eine eingebaute Bitfeld-Typ oder muss ich eine alternative Lösung zu finden?
Antworten
Zu viele Anzeigen?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.
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).
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.
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).
- See previous answers
- Weitere Antworten anzeigen