さて、いま作っているプロジェクトもpython3対応しようと、2to3.pyにかけてみた。
ワイルドカードで指定できなかったので、cygwinでxargsを使ったが、printがprint()になっているので変換できたのだろう。
よし、とpyCharmの設定もpython3にして開いてみると、指摘がたくさん。。。
こんなのが指摘されている。
struct.pack('<H', length).encode('hex')
bytes = lenstr.decode('hex')
hiro99ma blog: [py]python3は16進数の扱いが違うんだ
違うんだ、を実感した瞬間である。
decode/encodeはstr型用だから、bytes型だと使えない。
struct.pack()はbytes型で返すようになっている。
だから、bytes型の扱いに変換すればよいだけのことだ。
文字.decode('hex')は、bytes.fromhex(文字)にすればよいはずだ。
そこはそれで済みそうだが、"\xab\x12"のようにして作っていた文字列をbytes型に変換しないと、fromhex()したデータとの足し算というか連結ができないことがわかった。
これは、文字列の前に「b」を付けるだけでよいようだ。
と、やってみたのだが、bytesの要素をord()したりstruct.unpack()すると怒られる。。。
ord(cmd_bytes[0])
strがほしいのにintが渡されている、ということだった。
デバッガで見てみると、bytes配列の要素はint型になっていた。
そうか、ord()しなくてもいいんだ。。。
が、これはこれで別の問題が起きた。
辞書のkeyとして"\xab"のような値を使っていたのだが、これをbytes型にしないと検索できなくなった。
しかし、検索するのはbytesから1バイト取ってきたデータなので、そのままだとint型になってしまう。
よくわからんので、cmd_bytes[0].to_bytes(1, byteorder='little')、などとしてbytes型に変換して、動きはしたのだけど、ダサい。。。
4. 組み込み型 — Python 3.5.2 ドキュメント
なるほど、要素として取り出すとintになるから、サイズ1の配列として取り出せばよいのか。
cmd = cmd_bytes[pos: pos+1]
こんなのでよい。
数値にしたければ、cmd[0]とすればよいだけなので、こっちの方が扱いやすいな。
encode('hex')するのは目で読める文字にするとき、decode('hex')するのは実際のデータにするとき、という使い分けをしていた。
これは、bytes型にhex()というメソッドがあり、それでよかった。
私がbytes型を使うときのやり方をまとめると、こう。
- 文字列でエスケープシーケンスを使って16進数を表していた→あたまに「b」を付ける
- decode('hex')していた→bytes.fromhex()にする
- ord()していた→bytesを1要素として取り出す(data[3]など)
- bytes型として切り出したい→配列として取り出す(data[3:4]など)
- encode('hex')していた→hex()にする
struct.pack/unpack()は、to_bytes()もあるし、あまり使わないかも。
to_bytes()の逆はなさそうだから、unpack()は使うことになるか。。。あ、int.from_bytes()というのもあるようだ。
to_bytes()はメソッドなのに、from_bytes()はstaticメソッドなのはなんでだろう?
pyCharmで指摘が出ているのは、あからさまにbytes型になったと分かる箇所だけだ。
型指定がないから、引数でもらったものをdecode('hex')などとしていても、そこは出てない。
だから、たくさん指摘が出ていると思ったけど、氷山の一角なのだ。
2to3でやってくれよーと思ったのだが、これはちょっと無理だな。
また、変換しようとしていたpythonプロジェクトは、str型のbytearrayで扱う場合と、str型で16進数文字列を扱う場合が混在していて、あっちではstruct.pack/unpack、こっちではdecode/encode('hex')と、実にまとまりがない。
今回は、python3にするのだったら、もう一度書き直した方が早そうだ。。。
0 件のコメント:
コメントを投稿
コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。
注: コメントを投稿できるのは、このブログのメンバーだけです。