ブール値の配列のコンパクトな表現が必要です。Python には組み込みのビットフィールド型がありますか、それとも別の解決策を見つける必要がありますか?
12 に答える
主に、ビット フィールドに名前を付けて簡単に操作できるようにしたい場合 (たとえば、通信プロトコルで単一ビットとして表されるフラグを操作する場合)、How Do Iで説明されているように、ctypesの標準の Structure および Union 機能を使用できます。 Pythonでctype構造+ユニオンを適切に宣言しますか? - スタックオーバーフロー
たとえば、バイトの最下位 4 ビットを個別に操作するには、LittleEndianStructure で最下位から最上位の順に名前を付けます。共用体を使用して byte または 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)
4 つのビット (ここでは最上位から始めて印刷しましたが、これは印刷するとより自然に見えます) は 1、1、0、0、つまりバイナリの 0xc です。
Bitarrayは、最近同様のニーズがあったときに見つけた最良の答えでした。これは C 拡張であり (純粋な Python である BitVector よりもはるかに高速です)、そのデータを実際のビットフィールドに格納します (したがって、要素ごとに 1 バイトを使用するように見える numpy ブール配列よりも 8 倍のメモリ効率があります)。
最近バージョン 2.0 になったbitstringモジュールを見てください。バイナリ データはバイト配列としてコンパクトに格納され、簡単に作成、変更、分析できます。
BitString
バイナリ、8 進数、16 進数、整数 (ビッグまたはリトル エンディアン)、文字列、バイト、浮動小数点数、ファイルなどからオブジェクトを作成できます。
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 ですが、メモリと速度の点で適度に最適化されています。
それぞれの値を 2 の累乗で表します。
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"
これが意味をなさない場合は、16 進数表現をもう少し深く掘り下げてください。これは基本的に、埋め込み C アプリケーションでもブール値フラグを追跡する方法です (メモリが限られている場合)。
二項ビット演算子 !、&、|、^、>>、および << を使用します。それらは非常にうまく機能し、基礎となる C に直接実装されます。これは通常、基礎となるハードウェア上に直接存在します。
BitVector パッケージが必要な場合があります。私のpythonインストールには組み込まれていませんが、pythonサイトで簡単に追跡できます。
NumPy には、ビットフィールドを作成するために使用できる配列インターフェイスモジュールがあります。
ビットフィールドが短い場合は、おそらくstruct moduleを使用できます。それ以外の場合は、配列モジュールのラッパーのようなものをお勧めします。
また、 ctypes モジュールにはbitfieldsが含まれていますが、私自身は使用したことがありません。emptorに注意してください。
int (または long int) を使用して bool の配列 (または整数のセット) として表現する場合は、 http ://sourceforge.net/projects/pybitop/files/ を ご覧ください。
ビットフィールドの long int への挿入/抽出を提供します。最上位または最下位の「1」ビットを見つける。すべての 1 を数えます。ビット反転; 純粋な python ではすべて可能ですが、C でははるかに高速です。