Python3でprint("\xff")が0xffを出力しない件について
はじめに
何もわからなくて、キレそう。勢いにまかせて書いたので特にまとまっていない。
print("\xff")が0xffを出力しない
なにはともあれこれを見てくれ。
$ python --version Python 2.7.16 $ python -c 'print("\xff")' | xxd 00000000: ff0a ...
これはPython2を使った場合。バイナリを見ると0xffを出力していることがわかる。(0x0aは改行文字なので気にしないで)
予想通りの出力ですね。しかし、Python3ではこうならない。
$ python --version Python 3.7.2 $ python -c 'print("\xff")' | xxd 00000000: c3bf 0a ...
どういうことなの…
c3bfってなんなの
そう言えば、Python3のstr型はUnicode文字列を格納するための型だった。まさか、\xff
はUnicodeのコードポイント?
>>> print("\xff" == "\u00ff") True
なるほどなー…じゃあ、c3bf
はUnicode文字をUTF-8でエンコードした結果?
>>> "\xff".encode(encoding="utf8") b'\xc3\xbf'
なるほどなー…
bytes型で出力してみる
bytes型で出力すれば大丈夫だよな。
$ python -c 'print(b"\xff")' | xxd 00000000: 6227 5c78 6666 270a b'\xff'.
b'\xff'
をそのまま出力しているだと…
とりあえず、print()のドキュメントを見てみるか。
キーワードなしの引数はすべて、 str() がするように文字列に変換され
ということで、print()
にbytes型を渡してもstr()
でラップされた結果が出力されるようだ。
>>> str(b"\xff") "b'\\xff'"
どうすればいいんだ
sys.stdout.buffer.write("b\xff")
を使えばよさそう。
$ python -c 'import sys; sys.stdout.buffer.write(b"\xff")' | xxd 00000000: ff .
おわりに
文字コードには気をつけようね。それにしても、驚き最小の原則とはなんだったのか…