HOWTO · Python

Python の Bytes-Like Object Is Required Not STR エラーの修正

このチュートリアルでは、Python の str エラーではなく、バイトのようなオブジェクトが必要であると説明しています。

このページの内容

Python の TypeError「a bytes-like object is required, not ‘str’」は、bytes を必要とする操作にテキスト(str)が渡されたことを意味します。エラーが発生した呼び出し箇所で値を確認し、データに合った操作を選びましょう。API が bytes を必要とする場合はテキストをエンコードし、テキストとして処理する場合は bytes をデコードします。

「bytes-like object is required, not ‘str’」という TypeError の意味

このエラーメッセージは、型の不一致の両側を示しています。「Bytes-like object is required」は操作が受け付ける値を、「not ‘str’」は渡された値がテキストであることを表します。このエラーは、区切り文字を使う操作、バイナリファイルへの書き込み、ソケットへの送信などでよく発生します。該当する呼び出しを見つけ、引数がどこで読み込まれ、作成され、または変換されたのかをたどってください。

テキストとバイナリデータが一致しない理由

Python 3 では、str は Unicode 文字の並びであるテキストです。bytes は変更できないバイト値の並びで、エンコードされたテキスト、ファイル、ネットワークデータなどによく使われます。たとえバイト列が読みやすい文字を表していても、この2つは異なる型であり、そのまま置き換えることはできません。

エンコードは、UTF-8 などの文字エンコーディングを使ってテキストを bytes に変換します。デコードは、対応するエンコーディングを使って bytes をテキストとして解釈します。どちらを選ぶかは、データの意味と受け取り側の API が受け付ける型によって決まります。むやみに変換すると、型の不一致を見えにくくしたり、データを壊したりすることがあります。Python 2 では文字列の扱いが異なるため、その挙動を Python 3 のコードの判断に使わないでください。

テキストと bytes を境界で変換する

bytes を必要とする API に渡すときは、テキストに encode() を使います。テキスト処理に渡すときは bytes に decode() を使い、そのバイト列が生成されたときのエンコーディングを選びます。

変換を明示すると、コード上でテキストが bytes になり、再びテキストに戻る箇所が分かります。UTF-8 は、持ち運びやすい形式で保存または送信するテキストによく使われるエンコーディングです。次の操作が受け付ける型を確認するまでは、値を元の形式のまま保ちましょう。こうすると型の不一致を見つけやすくなり、バイナリデータをテキストとして誤って変換することも避けられます。

次の例を実行します。

このセクションのコードと表示されるラベルや出力は英語のままです。

text = "Hello, World!"
data = text.encode("utf-8")
print(data)
print(data.decode("utf-8"))
b'Hello, World!'
Hello, World!

出力の最初の行にある b 接頭辞は、値が bytes であることを示します。str(data) はエンコードの逆変換ではありません。バイト列の内容をデコードせず、b'Hello, World!' のような表現を表示する場合があります。bytes が UTF-8 のテキストで、次の操作が str を必要とする場合は、data.decode("utf-8") を使ってください。

ファイルとソケットのコードでエラーを解消する

バイナリモードで開いたファイルは bytes を返すか、書き込み時に bytes を受け付けます。テキストモードでは、読み書きの際にデコードまたはエンコードが行われます。バイナリデータの場合は値を bytes のまま保ち、parts = data.split(b",") のように bytes の区切り文字を使います。ファイルの内容が UTF-8 のテキストで、テキストとして操作したい場合は、先にデコードしてから parts = data.decode("utf-8").split(",") のようにテキストの区切り文字を使います。バイト列を読み込んだ値に str() を適用してもファイルがデコードされるわけではありません。

bytes を扱うソケットメソッドにも同じ型の境界が当てはまります。sock.sendall(b"hello") は bytes をそのまま渡します。メッセージがテキストから始まる場合は、たとえば sock.sendall(message.encode("utf-8")) のように明示的にエンコードしてください。これは引数の型についての説明です。実際にソケット通信を行うには、ソケットが接続済みであることや、相手側とのプロトコルも関係します。

変換を選ぶ前に値を確認する

エラーが発生した操作の箇所で type(value) を調べるか、isinstance(value, bytes) と isinstance(value, str) を使ってください。次に API が必要とする型を確認し、その値がテキストなのか任意のバイナリデータなのかを判断して、必要な変換をその境界で一度だけ行います。テキストならファイルまたはプロトコルで使われているエンコーディングを選びます。任意のバイナリデータなら bytes のまま保ち、bytes を受け付ける区切り文字や操作に切り替えます。こうすれば、表示された値の見た目から推測せずに型の不一致を解消できます。