(ビッグエンディアン)可変サイズのバイナリバイト配列を(符号なし)整数/長整数型に変換するにはどうすればよいですか?例として、'\x11\x34'
、4404を表します
今、私は使用しています
def bytes_to_int(bytes):
return int(bytes.encode('hex'), 16)
これは小さく、多少読みやすいですが、おそらくあまり効率的ではありません。より良い(より明白な)方法はありますか?
Pythonは従来、Cには大きすぎる「ビッグエンディアンCレイアウトの数値」をあまり使用していません。(2バイト、4バイト、または8バイトの数値を扱う場合は、_struct.unpack
_が答えです。)
しかし、十分な人々はPython 3.2がメソッドを追加しました _int.from_bytes
_ これはまさにあなたが望むことをする1つの明白な方法がないことにうんざりしました:
_int.from_bytes(b, byteorder='big', signed=False)
_
残念ながら、古いバージョンのPythonを使用している場合、これはありません。それで、あなたにはどんなオプションがありますか? (明らかなものに加えて、3.2へのアップデート、またはより良い、3.4…)
まず、コードがあります。 _binascii.hexlify
_は.encode('hex')
よりもスペルの良い方法だと思います。なぜなら、「encode」はバイト文字列のメソッド(Unicode文字列とは対照的に)で常に少し奇妙に見え、実際にはPython 3.で追放されました。しかし、それ以外の場合は、非常に読みやすく、私にとっては明らかです。そして、それは非常に高速である必要があります。 Cでのループと算術(少なくともCPython)。これは一般にPythonよりも1桁または2倍高速です。bytearray
が大きすぎて文字列の割り当て自体がコストがかかる場合を除き、ここでパフォーマンスを心配します。
または、ループで実行することもできます。しかし、それはより冗長になり、少なくともCPythonでははるかに遅くなります。
暗黙のループの明示的なループを排除しようとすることもできますが、それを行うための明白な関数はreduce
です。これはコミュニティの一部によって非Python的であると見なされます。各バイト。
ループまたはreduce
を展開するには、8バイトのチャンクに分割して_struct.unpack_from
_をループするか、大きなstruct.unpack('Q'*len(b)//8 + 'B' * len(b)%8)
を実行してループしますが、読みにくく、おそらくそれほど速くはありません。
NumPyを使用することもできますが、64または128ビットよりも大きくなると、すべてをPythonオブジェクトに変換することになります。
ですから、あなたの答えが最良の選択肢だと思います。
最も明らかな手動変換と比較するタイミングを次に示します。
_import binascii
import functools
import numpy as np
def hexint(b):
return int(binascii.hexlify(b), 16)
def loop1(b):
def f(x, y): return (x<<8)|y
return functools.reduce(f, b, 0)
def loop2(b):
x = 0
for c in b:
x <<= 8
x |= c
return x
def numpily(b):
n = np.array(list(b))
p = 1 << np.arange(len(b)-1, -1, -1, dtype=object)
return np.sum(n * p)
_
_In [226]: b = bytearray(range(256))
In [227]: %timeit hexint(b)
1000000 loops, best of 3: 1.8 µs per loop
In [228]: %timeit loop1(b)
10000 loops, best of 3: 57.7 µs per loop
In [229]: %timeit loop2(b)
10000 loops, best of 3: 46.4 µs per loop
In [283]: %timeit numpily(b)
10000 loops, best of 3: 88.5 µs per loop
_
Python 3.4:
_In [17]: %timeit hexint(b)
1000000 loops, best of 3: 1.69 µs per loop
In [17]: %timeit int.from_bytes(b, byteorder='big', signed=False)
1000000 loops, best of 3: 1.42 µs per loop
_
だから、あなたの方法はまだかなり速いです...
関数 struct.unpack(...) は必要なことを行います。