静かなる名辞

pythonとプログラミングのこと


Pythonの文字列メソッドとバイト列の微妙な関係

 Python3になってからは普段あまり気にしなくても良いようになりましたが、Pythonの文字列っぽい型にはstrとbytesがあります*1。そして、strもbytesも同じようなメソッドを実装してくれています。

組み込み型 — Python 3.8.2 ドキュメント

組み込み型 — Python 3.8.2 ドキュメント

>>> [x for x in dir(str) if "__" not in x] 
['capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
>>> [x for x in dir(bytes) if "__" not in x] 
['capitalize', 'center', 'count', 'decode', 'endswith', 'expandtabs', 'find', 'fromhex', 'hex', 'index', 'isalnum', 'isalpha', 'isdigit', 'islower', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']

 完全に互換という訳でもないようですが、それでもだいたい同じ操作がサポートされています。

 問題は、strとbytesを混在させて使えないことです。

 splitで見てみます。

>>> "a,b,c".split(b",")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Can't convert 'bytes' object to str implicitly
>>> b"a,b,c".split(",")
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: a bytes-like object is required, not 'str'

 エラーを回避するためには、型を合わせる必要があります。strのメソッドならstrを、bytesのメソッドならbytesを渡してあげてください。

>>> "a,b,c".split(",")
['a', 'b', 'c']
>>> b"a,b,c".split(b",")
[b'a', b'b', b'c']

 駄目押しで、joinでも見てみます。

>>> ",".join([b'a', b'b', b'c'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sequence item 0: expected str instance, bytes found
>>> b",".join(['a', 'b', 'c'])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: sequence item 0: expected a bytes-like object, str found

 やっぱりできません。

 逆にこの点に注意しておけば、bytesのまま扱うことも可能ですが、実際問題としてはなかなか厄介です。素直に入力された時点でstrにデコードしてしまうことをおすすめします。str→bytes変換はencode, 逆はdecodeメソッドです。

*1:すべてPython3準拠で説明します。さすがにPython2はもういいでしょ