Python 3で文字列をバイトに変換する最良の方法?


860

TypeErrorへの回答に示されているように、文字列をバイトに変換するには2つの異なる方法があるようです: 'str'はバッファーインターフェイスをサポートしていません

これらの方法のうち、Pythonicの方が優れているか、より優れているでしょうか?それとも個人的な好みの問題ですか?

b = bytes(mystring, 'utf-8')

b = mystring.encode('utf-8')

42
エンコード/デコードの使用がより一般的で、おそらくより明確です。
Lennart Regebro、2009

11
@LennartRegebro却下します。それがより一般的であるとしても、「bytes()」を読んで私はそれが何をしているのか知っていますが、encode()はバイトにエンコードしていると感じさせません。
m3nda 2017

2
@それはまでそれを使用するための良い理由であるerm3nda 、そして、あなたがそのように感じるが、一歩近づくのUnicode禅へ。
Lennart Regebro 2017

4
@LennartRegebro bytes(item, "utf8")明示的に暗黙よりも明示的の方がいいので、を使用するだけで十分です。str.encode( )デフォルトでは暗黙的にバイトになり、Unicode禅は多くなりますが、Explicit禅は少なくなります。また、「一般的」は私が従うのが好きな用語ではありません。また、、、およびの表記にbytes(item, "utf8")似ています。私があなたの理由を理解するのがとても不慣れであるならば、私の謝罪。ありがとうございました。str()b"string"
m3nda 2017

4
@ erm3nda受け入れられた回答を読むencode()bytes()、それがを呼び出さないことがわかります。それは逆です。もちろん、それがすぐにわかるわけではないので、私が質問したのはそのためです。
Mark Ransom

回答:


571

のドキュメントを見ると、次のことがわかりbytesますbytearray

bytearray([ソース[、エンコーディング[、エラー]]])

バイトの新しい配列を返します。bytearrayタイプは、0 <= x <256の範囲の整数の可変シーケンスです。可変シーケンスタイプで説明されている可変シーケンスの通常のメソッドのほとんどと、バイトタイプが持つほとんどのメソッドがあります。バイトとバイト配列メソッド。

オプションのsourceパラメータを使用して、いくつかの異なる方法で配列を初期化できます。

文字列の場合は、エンコーディング(およびオプションでエラー)パラメータも指定する必要があります。次に、bytearray()はstr.encode()を使用して文字列をバイトに変換します。

整数の場合、配列はそのサイズになり、nullバイトで初期化されます。

バッファインターフェースに準拠したオブジェクトの場合、バイト配列を初期化するためにオブジェクトの読み取り専用バッファが使用されます。

反復可能である場合は、配列の初期コンテンツとして使用される0 <= x <256の範囲の整数の反復可能でなければなりません。

引数がない場合、サイズ0の配列が作成されます。

つまりbytes、文字列をエンコードするだけではありません。意味のある任意のタイプのソースパラメータを使用してコンストラクタを呼び出すことができるのはPythonicです。

文字列をエンコードするsome_string.encode(encoding)場合、それは最も自己文書化されているため、コンストラクタを使用するよりもPythonic だと思います。「この文字列を取得し、このエンコードでエンコードする」よりも明確bytes(some_string, encoding)です。使用するときに明示的な動詞はありませんコンストラクタ。

編集: Pythonソースを確認しました。bytesCPython を使用してUnicode文字列を渡すと、PyUnicode_AsEncodedString呼び出さencodeます。これはの実装です。したがって、encode自分を呼び出す場合は、間接参照のレベルをスキップしているだけです。

また、Serdalisのコメントを参照してください。unicode_string.encode(encoding)その逆byte_string.decode(encoding)と対称性が優れているため、Pythonicでもあります。


73
+1は、Pythonのドキュメントから適切な議論と引用を得たものです。また、文字列を元に戻したいときにもunicode_string.encode(encoding)一致しbytearray.decode(encoding)ます。
Serdalis '09

6
bytearray変更可能なオブジェクトが必要な場合に使用されます。単純なstrbytes変換には必要ありません。
hamstergene 2011

8
@EugeneHomyakovこれはbytearray、ドキュメントにbytes詳細が記載されていないことを除いて、何の関係もありません。「これは不変バージョンですbytearray」と言うだけなので、そこから引用する必要があります。
agf 2011

1
Pythonから一言で言えば、次の注意点がありbytesます。整数型の引数を持つ関数としてbytes型を使用しないでください。v2ではstrのエイリアスであるため、これは整数を(バイト)文字列に変換して返しますが、v3では指定された数のnull文字を含むバイト文字列を返します。したがって、たとえば、v3式bytes(6)の代わりに、同等のb '\ x00' * 6を使用します。これは、各バージョンで同じようにシームレスに機能します。
holdenweb 2017

2
ただ、ノート、あなたがバイナリデータを文字列に変換しようとしている場合は、あなたのような使用のものに最も可能性が高い必要があることbyte_string.decode('latin-1')などutf-8の0xFF(0〜255)の全範囲は0x00をカバーしていない、Pythonのチェックアウトドキュメントのためにより詳しい情報。
iggy12345

349

思ったより簡単です。

my_str = "hello world"
my_str_as_bytes = str.encode(my_str)
type(my_str_as_bytes) # ensure it is byte representation
my_decoded_str = my_str_as_bytes.decode()
type(my_decoded_str) # ensure it is string representation

37
彼はそれを行う方法を知っています、彼はどちらがより良い方法を求めているだけです。質問をもう一度読んでください。
agf 2013

30
参考:str.decode(bytes)が機能しませんでした(Python 3.3.3は「タイプオブジェクト 'str'には属性 'decode'がありません」と言っていました)代わりにbytes.decode()を使用しました
Mike

6
@マイク:obj.method()構文の代わりにcls.method(obj)構文を使用bytestring = unicode_text.encode(encoding)unicode_text = bytestring.decode(encoding)ます。つまり、およびを使用します。
jfs

2
...つまり、不必要にバインドされていないメソッドを作成し、それをself最初の引数として渡して呼び出す
Antti Haapala

2
@KolobCanyon質問はすでに正しい方法を示してencodeいます。文字列のバインドされたメソッドとして呼び出します。この答えは、代わりにunboundメソッドを呼び出して文字列を渡す必要があることを示唆しています。それは答えの中で唯一の新しい情報であり、それは間違っています。
abarnert

144

絶対に最良の方法は、2のどちらであるが、第3回。Python 3.0以降、デフォルトの最初のパラメータはこれまでです。したがって、最良の方法はencode 'utf-8'

b = mystring.encode()

デフォルトの引数の結果"utf-8"はCコードの文字列ではないため、これも高速になりますがNULL、チェックははるかに高速です!

ここにいくつかのタイミングがあります:

In [1]: %timeit -r 10 'abc'.encode('utf-8')
The slowest run took 38.07 times longer than the fastest. 
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 183 ns per loop

In [2]: %timeit -r 10 'abc'.encode()
The slowest run took 27.34 times longer than the fastest. 
This could mean that an intermediate result is being cached.
10000000 loops, best of 10: 137 ns per loop

警告にもかかわらず、繰り返し実行した後の時間は非常に安定しており、偏差はわずか2%でした。


encode()引数なしで使用すると、Python 2と互換性がありません。Python2では、デフォルトの文字エンコーディングはASCIIです。

>>> 'äöä'.encode()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc3 in position 0: ordinal not in range(128)

2
(a)文字列が純粋なASCIIであるため、内部ストレージがすでにUTF-8バージョンであるため、コーデックの検索がほとんど唯一のコストであり、(b)文字列が小さいため、ここには大きな違いがあります。なので、エンコードする必要があったとしても、それほど大きな違いはありません。と言ってみてください'\u00012345'*10000。私のラップトップではどちらも28.8usかかります。余分な50nsは、おそらく丸め誤差で失われます。もちろん、これはかなり極端な例ですが'abc'、反対方向にも同じように極端です。
abarnert

@abarnertはtrueですが、それでも、引数を文字列として渡す理由はありません。
Antti Haapala

これによると、デフォルトの引数は常に「絶対に最善の方法」で物事を行うのですよね?この種の速度分析は、これがCコードの議論に関するものである場合、おそらく誇張のように感じられます。インタプリタ言語では、それは私に言葉を失います。
hmijailが辞任者を悼む
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.