Pergunta

Eu preciso de uma representação compacta de um array de booleanos, não Python tem um tipo interno bitfield ou I terá que encontrar uma solução alternativa?

Foi útil?

Solução

BitArray foi a melhor resposta que eu encontrei, quando eu tive recentemente uma necessidade similar. É uma extensão C (muito mais rápido do que BitVector, que é pura python) e armazena seus dados em um campo de bits real (por isso é oito vezes mais memória eficiente do que uma matriz booleana numpy, que parece usar um byte por elemento.)

Outras dicas

Se você quiser, principalmente para ser capaz de nomear os campos bit e facilmente manipulá-los, por exemplo, Para trabalhar com bandeiras representadas como bits individuais em um protocolo de comunicações, então você pode usar a estrutura padrão e União dispõe de ctypes , conforme descrito em Como eu corretamente Declare uma estrutura ctype + União em Python? - Stack Overflow

Por exemplo, para o trabalho com os 4 bits menos significativos de um byte individualmente, apenas nomeá-los do menos ao mais significativo em um LittleEndianStructure. Você usa uma união para fornecer acesso aos mesmos dados como um byte ou int para que possa mover os dados dentro ou fora do protocolo de comunicação. Neste caso, o que é feito através do 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)

Os quatro bits (que eu impressos aqui começando com o mais significativo, o que parece mais natural quando se imprime) são 1, 1, 0, 0, ou seja 0xc em binário.

Você deve dar uma olhada na bitstring módulo, que chegou recentemente a versão 2.0 . Os dados binários são compactamente armazenado como uma matriz de bytes e pode ser facilmente criado, modificada e analisada.

Você pode criar objetos BitString de binário, octal, hexadecimal, inteiros (endian grande ou pequena), cordas, bytes, flutuadores, arquivos e muito mais.

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

Você pode, então, analisar e modificá-los com funções simples ou notação slice -. Não há necessidade de se preocupar com máscaras 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'

Há também um conceito de uma posição pouco, de modo que você pode tratá-lo como um arquivo ou fluxo se isso é útil. Propriedades são usadas para dar diferentes interpretações dos dados 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

Além disso, há suporte para os operadores binários bit a bit padrão, embalagem, desembalagem, endianness e muito mais. A última versão é para Python 2.7 e 3.x, e embora seja pura Python é razoavelmente bem otimizado em termos de memória e velocidade.

Eu uso os operadores bit a bit binários, &, |!, ^, >> e <<. Eles trabalham muito bem e são implementados diretamente na C subjacente, que é geralmente diretamente no hardware subjacente.

representam cada um de seus valores como uma potência de dois:

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

Depois de definir um valor verdadeiro:

table = table | testB

Para definir um valor falso:

table = table & (~testC)

Para teste para um valor:

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

Dig um pouco mais em representação hexadecimal se isso não faz sentido para você. Esta é, basicamente, como você manter o controle de suas bandeiras booleanas em um aplicativo C incorporado, bem como (se tiver limitted memória).

O pacote BitVector pode ser o que você precisa. Não é construído para minha instalação python, mas fácil de rastrear no site python.

https://pypi.python.org/pypi/BitVector para a versão atual .

NumPy tem um variedade módulo de interface que você pode usar para fazer um campo de bits.

Se o seu bitfield é curto, você provavelmente pode usar o struct módulo . Caso contrário, eu recomendo algum tipo de um invólucro em torno o módulo de conjunto .

Além disso, o módulo ctypes contém bitfields , mas eu nunca usei isso mesmo. caveat.emptor .

Se você quiser usar ints (ou inteiros longos) para representar como matrizes de bools (ou como conjuntos de números inteiros), dê uma olhada em http://sourceforge.net/projects/pybitop/files/

Ele fornece inserção / extracção de bitfields em longas ints; encontrar o '1' bit mais significativo, ou menos significativo; contando todos os 1s; -bit reversão; coisas assim que é possível em python puro, mas muito mais rápido em C.

Para pedaços principalmente consecutivos, há o https://pypi.org/project/range_set/ módulo que é API compatível com set built-in de Python. Como o nome indica, ele armazena os bits como começar / pares finais.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top