銀月の符号

Python 使い見習いの日記・雑記

Python 3 の bytes 型は数値の配列

自作のおもちゃライブラリを 2to3.py して Python 3 で動かしてみたが、うまくいかなかったものがあった。ちょっと調べていくと原因が見つかったのでメモ。

bytes にインデックスアクセスしたりイテレータを要求する箇所で用いたりすると int が返る。 Python 2 の chr は chr を返していたので明らかに異なる。

>>> b'abc'[0]
97
>>> iter(b'abc')
<bytes_iterator object at 0x00B9E110>
>>> next(_)
97
>>> for i in b'abc':
...   print(i)
...
97
98
99
>>> list(b'abc')
[97, 98, 99]
>>> print(*b'abc')
97 98 99

bytes 型には数値の配列という要素が Python 2 の str より色濃く出ている。


今回はまったのはバイト列を数値の配列としてみて、 1 ビットずつ処理するようなコードだった。数値の配列を得る方法の違いが原因。 Python 2 だと ord を用いて str を int に直す必要があった。 Python 3 だと ord はいらない。

次のコードを Python 3 で処理すると c は整数となり、整数にさらに ord をかけてしまうことになる。 TypeError。

>>> for i in (ord(c) for c in b'abc'):
...   print i
...
97
98
99

でも、こう書いておくと両対応する。 Python 2 では c は str (バイト列)。 Python 3 では str(ユニコード文字列)。そしてユニコード文字列 c に対して ord をかけるのはなんら問題がない。結果オーライだがちょっと納得いかない。

>>> for i in (ord(c) for c in 'abc'):
...   print(i)
...
97
98
99

Python 3 対応を見越してバイト列を b'' リテラルで書いたのが、逆にあだとなった事例だった。というか Python 3 ろくにつかってないことがバレるなこれ。

ちなみに、今回問題があったおもちゃとは「ケンシロウ進数」変換を行うライブラリだった。あたたたたた。