Есть ли у Python тип битового поля? - PullRequest
43 голосов
/ 27 сентября 2008

Мне нужно компактное представление массива логических значений, имеет ли Python встроенный тип битового поля или мне нужно будет найти альтернативное решение?

Ответы [ 10 ]

30 голосов
/ 14 июля 2012

Если вы в основном хотите иметь возможность называть свои битовые поля и легко ими манипулировать, например, для работы с флагами, представленными в протоколе связи как отдельные биты, вы можете использовать стандартные функции структуры и объединения ctypes , как описано в Как правильно объявить структуру ctype + Union в Python ? - Переполнение стека

Например, для индивидуальной работы с 4 наименее значимыми битами байта просто назовите их от наименее значимых до наиболее значимых в LittleEndianStructure. Вы используете объединение для предоставления доступа к тем же данным, что и байты или int, чтобы вы могли перемещать данные в протокол связи или из него. В этом случае это делается через поле 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)

Четыре бита (которые я напечатал здесь, начиная с самого значительного, что кажется более естественным при печати), равны 1, 1, 0, 0, то есть 0xc в двоичном формате.

29 голосов
/ 27 сентября 2008

Bitarray был лучшим ответом, который я нашел, когда у меня недавно была похожая потребность. Это расширение C (намного быстрее, чем BitVector, который является чистым Python), и хранит свои данные в реальном битовом поле (так что оно в восемь раз эффективнее памяти, чем массивный логический массив, который, похоже, использует байт на элемент.) *

12 голосов
/ 16 октября 2009

Вы должны взглянуть на модуль bitstring , который недавно достиг версии 2.0. Двоичные данные компактно хранятся в виде байтового массива и могут быть легко созданы, изменены и проанализированы.

Вы можете создавать BitString объекты из двоичных, восьмеричных, шестнадцатеричных, целых чисел (с прямым или младшим порядковым номером), строк, байтов, чисел с плавающей точкой, файлов и т.

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

Затем вы можете анализировать и изменять их с помощью простых функций или обозначений срезов - не нужно беспокоиться о битовых масках и т. Д.

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'

Существует также концепция битовой позиции, так что вы можете рассматривать ее как файл или поток, если это полезно для вас. Свойства используются для различных интерпретаций битовых данных.

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

Плюс есть поддержка стандартных побитовых двоичных операторов, упаковка, распаковка, порядковый номер и многое другое. Последняя версия предназначена для Python 2.7 и 3.x, и хотя это чистый Python, он достаточно хорошо оптимизирован с точки зрения памяти и скорости.

6 голосов
/ 05 ноября 2008

Представьте каждое из ваших значений как степень двух:

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

Затем, чтобы установить значение true:

table = table | testB

Чтобы установить значение false:

table = table & (~testC)

Чтобы проверить значение:

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

Погрузитесь немного глубже в шестнадцатеричное представление, если это не имеет смысла для вас. Это в основном то, как вы отслеживаете свои логические флаги и во встроенном C-приложении (если у вас ограниченная память).

6 голосов
/ 27 сентября 2008

Я использую двоичные побитовые операторы!, &, |, ^, >> и <<. Они действительно хорошо работают и реализуются непосредственно в базовом C, который обычно находится непосредственно на базовом оборудовании. </p>

5 голосов
/ 27 сентября 2008

Пакет BitVector может быть тем, что вам нужно. Он не встроен в мою установку на python, но его легко отследить на сайте python.

https://pypi.python.org/pypi/BitVector для текущей версии.

4 голосов
/ 27 сентября 2008

NumPy имеет интерфейс массива модуль, который вы можете использовать для создания битового поля.

2 голосов
/ 27 сентября 2008

Если ваше битовое поле короткое, вы, вероятно, можете использовать модуль struct . В противном случае я бы порекомендовал какую-то оболочку вокруг модуля массива .

Кроме того, модуль ctypes содержит битовые поля , но я никогда не использовал его сам. Предостережение emptor .

1 голос
/ 17 сентября 2010

Если вы хотите использовать целые числа (или длинные целые числа) для представления в виде массивов значений типа bools (или наборов целых чисел), взгляните на http://sourceforge.net/projects/pybitop/files/

Обеспечивает вставку / извлечение битовых полей в длинные целые числа; поиск наиболее значимого или наименее значимого бита «1»; считая все 1; инвертирования битов; такие вещи, которые возможны в чистом питоне, но гораздо быстрее в C.

0 голосов
/ 31 декабря 2018

Для большей части последовательных битов есть модуль https://pypi.org/project/range_set/, который API-совместим со встроенным в Python set. Как следует из названия, биты хранятся в виде пар начала / конца.

...