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 ろくにつかってないことがバレるなこれ。
ちなみに、今回問題があったおもちゃとは「ケンシロウ進数」変換を行うライブラリだった。あたたたたた。