Domanda

Ho bisogno di una rappresentazione compatta di un array di valori booleani, Python ha un tipo di bitfield incorporato o dovrò trovare una soluzione alternativa?

È stato utile?

Soluzione

Bitarray è stata la migliore risposta che ho trovato, quando recentemente ho avuto un bisogno simile. È un'estensione C (molto più veloce di BitVector, che è puro Python) e memorizza i suoi dati in un campo reale (quindi è otto volte più efficiente in termini di memoria di un array booleano intorpidito, che sembra usare un byte per elemento.)

Altri suggerimenti

Se vuoi principalmente poter nominare i tuoi campi bit e manipolarli facilmente, ad es. per lavorare con i flag rappresentati come bit singoli in un protocollo di comunicazione, è possibile utilizzare le funzionalità standard Struttura e Unione di ctypes , come descritto in Come posso dichiarare correttamente una ctype Structure + Union in Python? - StackTranslate.it

Ad esempio, per lavorare individualmente con i 4 bit meno significativi di un byte, nominali dal meno al più significativo in una struttura LittleEndian. Si utilizza un'unione per fornire l'accesso agli stessi dati di un byte o int in modo da poter spostare i dati dentro o fuori dal protocollo di comunicazione. In questo caso ciò avviene tramite il campo flags.asbyte:

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)

I quattro bit (che ho stampato qui iniziando con il più significativo, che sembra più naturale durante la stampa) sono 1, 1, 0, 0, ovvero 0xc in binario.

Dovresti dare un'occhiata al modulo bitstring , che ha recentemente raggiunto la versione 2.0 . I dati binari sono archiviati in modo compatto come una matrice di byte e possono essere facilmente creati, modificati e analizzati.

Puoi creare BitString oggetti da binario, ottale, esadecimale, numeri interi (big o little endian), stringhe, byte, float, file e altro.

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

È quindi possibile analizzarli e modificarli con semplici funzioni o notazione di sezioni - non è necessario preoccuparsi di maschere di bit, ecc.

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'

Esiste anche un concetto di posizione bit, in modo che tu possa trattarlo come un file o flusso se ti è utile. Le proprietà vengono utilizzate per fornire diverse interpretazioni dei dati bit.

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

Inoltre c'è il supporto per gli operatori binari bit-saggio standard, imballaggio, disimballaggio, endianness e altro. L'ultima versione è per Python 2.7 e 3.x, e sebbene sia Python puro è ragionevolmente ben ottimizzato in termini di memoria e velocità.

Uso gli operatori binari bit-saggio!, & amp ;, |, ^, > > ;, e < < ;. Funzionano davvero bene e sono implementati direttamente nella C sottostante, che di solito si trova direttamente sull'hardware sottostante.

Rappresenta ciascuno dei tuoi valori come una potenza di due:

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

Quindi, per impostare un valore vero:

table = table | testB

Per impostare un valore falso:

table = table & (~testC)

Per verificare un valore:

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

Scava un po 'più a fondo nella rappresentazione esadecimale se questo non ha senso per te. Questo è fondamentalmente il modo in cui tieni traccia dei tuoi flag booleani anche in un'applicazione C incorporata (se hai limitato la memoria).

Il pacchetto BitVector potrebbe essere quello che ti serve. Non è integrato nella mia installazione di Python, ma è facile da rintracciare sul sito Python.

https://pypi.python.org/pypi/BitVector per la versione corrente .

NumPy ha un interfaccia array che puoi usare per creare un bitfield.

Se il tuo bitfield è breve, probabilmente puoi utilizzare il modulo struct . Altrimenti consiglierei una sorta di wrapper per il modulo array .

Inoltre, il modulo ctypes contiene bitfields , ma non l'ho mai usato da solo. Caveat emptor .

Se vuoi usare ints (o long ints) per rappresentare come array di bool (o come set di numeri interi), dai un'occhiata a http://sourceforge.net/projects/pybitop/files/

Fornisce inserimento / estrazione di bitfield in long ints; trovare il bit '1' più significativo o meno significativo; contando tutti gli 1; bit-inversione; cose come quelle che sono tutte possibili in puro pitone ma molto più veloci in C.

Per bit prevalentemente consecutivi c'è il https://pypi.org/project/range_set/ modulo che è API compatibile con il built-in set di Python. Come suggerisce il nome, memorizza i bit come coppie di inizio / fine.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top