Cara terbaik untuk mengkonversi string ke byte di Python 3?

861

Tampaknya ada dua cara berbeda untuk mengubah string menjadi byte, seperti terlihat pada jawaban untuk TypeError: 'str' tidak mendukung antarmuka buffer

Manakah dari metode ini yang lebih baik atau lebih Pythonic? Atau itu hanya masalah preferensi pribadi?

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

b = mystring.encode('utf-8')
Mark tebusan
sumber
42
Penggunaan encode / decode lebih umum, dan mungkin lebih jelas.
Lennart Regebro
11
@LennartRegebro saya abaikan. Bahkan jika itu lebih umum, membaca "bytes ()" saya tahu apa yang dilakukannya, sementara encode () jangan membuat saya merasa itu encoding ke byte.
m3nda
2
@ erm3nda Yang merupakan alasan yang baik untuk menggunakannya sampai tidak merasa seperti itu, maka Anda adalah salah satu langkah lebih dekat untuk Unicode zen.
Lennart Regebro
4
@LennartRegebro Saya merasa cukup baik untuk hanya menggunakan bytes(item, "utf8"), karena eksplisit lebih baik daripada implisit, jadi ... str.encode( )default secara diam-diam ke byte, membuat Anda lebih Unicode-zen tetapi kurang Eksplisit-Zen. Juga "umum" bukan istilah yang ingin saya ikuti. Juga, bytes(item, "utf8")lebih seperti str(), dan b"string"notasi. Saya minta maaf jika saya sangat tidak mengerti alasan Anda. Terima kasih.
m3nda
4
@ erm3nda jika Anda membaca jawaban yang diterima Anda dapat melihat bahwa encode()tidak menelepon bytes(), itu sebaliknya. Tentu saja itu tidak segera jelas karena itulah saya mengajukan pertanyaan.
Mark Ransom

Jawaban:

571

Jika Anda melihat dokumen untuk bytes, itu mengarahkan Anda ke bytearray:

bytearray ([sumber [, penyandian [, kesalahan]]])

Kembalikan array byte baru. Tipe bytearray adalah urutan bilangan bulat yang dapat berubah dalam kisaran 0 <= x <256. Ia memiliki sebagian besar metode urutan urutan yang dapat berubah, yang dijelaskan dalam Jenis Urutan yang Dapat Dimatikan, serta sebagian besar metode yang dimiliki tipe byte, lihat Bytes dan Metode Array Byte.

Parameter sumber opsional dapat digunakan untuk menginisialisasi array dengan beberapa cara berbeda:

Jika ini adalah string, Anda juga harus memberikan parameter penyandian (dan opsional, kesalahan); bytearray () kemudian mengonversi string menjadi byte menggunakan str.encode ().

Jika bilangan bulat, array akan memiliki ukuran itu dan akan diinisialisasi dengan byte nol.

Jika itu adalah objek yang sesuai dengan antarmuka buffer, buffer read-only dari objek akan digunakan untuk menginisialisasi array byte.

Jika iterable, itu harus iterable dari integer dalam rentang 0 <= x <256, yang digunakan sebagai konten awal array.

Tanpa argumen, array ukuran 0 dibuat.

Jadi bytesbisa melakukan lebih dari sekadar menyandikan string. Ini Pythonic yang akan memungkinkan Anda untuk memanggil konstruktor dengan segala jenis parameter sumber yang masuk akal.

Untuk pengkodean string, saya pikir itu some_string.encode(encoding)lebih Pythonic daripada menggunakan konstruktor, karena itu adalah yang paling mendokumentasikan diri - "ambil string ini dan kodekan dengan pengkodean ini" lebih jelas daripada bytes(some_string, encoding)- tidak ada kata kerja eksplisit ketika Anda menggunakan konstruktor.

Sunting: Saya memeriksa sumber Python. Jika Anda melewatkan string unicode bytesmenggunakan CPython, ia memanggil PyUnicode_AsEncodedString , yang merupakan implementasi dari encode; jadi Anda hanya melewatkan tingkat tipuan jika Anda memanggil encodediri sendiri.

Juga, lihat komentar Serdalis - unicode_string.encode(encoding)juga lebih Pythonic karena kebalikannya byte_string.decode(encoding)dan simetrinya bagus.

agf
sumber
73
+1 karena memiliki argumen dan kutipan yang bagus dari python docs. Juga unicode_string.encode(encoding)cocok dengan bytearray.decode(encoding)ketika Anda ingin kembali string Anda.
Serdalis
6
bytearraydigunakan ketika Anda membutuhkan objek yang bisa berubah. Anda tidak memerlukannya untuk konversi str↔ sederhana bytes.
hamstergene
8
@EugeneHomyakov Ini tidak ada hubungannya dengan bytearraykecuali bahwa dokumen untuk bytestidak memberikan rincian, mereka hanya mengatakan "ini adalah versi abadi bytearray" jadi saya harus mengutip dari sana.
agf
1
Hanya catatan peringatan dari Python dalam Singkatnya tentang bytes: Hindari menggunakan tipe byte sebagai fungsi dengan argumen integer. Di v2 ini mengembalikan integer yang dikonversi ke string (byte) karena byte adalah alias untuk str, sementara di v3 ia mengembalikan bytestring yang berisi jumlah karakter null yang diberikan. Jadi, misalnya, alih-alih byte ekspresi v3 (6), gunakan setara b '\ x00' * 6, yang bekerja mulus dengan cara yang sama di setiap versi.
holdenweb
2
Hanya sebuah catatan, bahwa jika Anda mencoba mengonversi data biner ke string, kemungkinan besar Anda perlu menggunakan sesuatu seperti byte_string.decode('latin-1')karena utf-8tidak mencakup seluruh rentang 0x00 hingga 0xFF (0-255), periksa dokumentasi python untuk Info lebih lanjut.
iggy12345
349

Lebih mudah dari yang diperkirakan:

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
hasanatkazmi
sumber
37
Dia tahu bagaimana melakukannya, dia hanya bertanya jalan mana yang lebih baik. Harap baca kembali pertanyaannya.
agf
30
FYI: str.decode (byte) tidak bekerja untuk saya (Python 3.3.3 mengatakan "ketik objek 'str' tidak memiliki atribut 'decode'") Saya menggunakan bytes.decode () sebagai gantinya
Mike
6
@ Mike: gunakan obj.method()sintaks bukan cls.method(obj)sintaks yaitu, gunakan bytestring = unicode_text.encode(encoding)dan unicode_text = bytestring.decode(encoding).
jfs
2
... yaitu Anda tidak perlu membuat metode yang tidak terikat, dan kemudian menyebutnya lewat selfargumen pertama
Antti Haapala
2
@KolobCanyon Pertanyaan sudah menunjukkan cara yang tepat untuk melakukannya — panggil encodesebagai metode terikat pada string. Jawaban ini menunjukkan bahwa Anda sebaiknya memanggil metode tidak terikat dan meneruskannya string. Itulah satu-satunya informasi baru dalam jawabannya, dan itu salah.
abarnert
144

The benar-benar cara terbaik adalah tidak satu pun dari 2, tetapi 3. Parameter pertama ke default sejak Python 3.0. Demikian cara terbaiknyaencode 'utf-8'

b = mystring.encode()

Ini juga akan lebih cepat, karena argumen default tidak menghasilkan string "utf-8"dalam kode C, tetapi NULL, yang jauh lebih cepat untuk diperiksa!

Berikut ini beberapa timing:

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

Meskipun ada peringatan, waktunya sangat stabil setelah berjalan berulang kali - penyimpangannya hanya ~ 2 persen.


Menggunakan encode()tanpa argumen tidak kompatibel dengan Python, seperti pada Python 2 pengkodean karakter default adalah 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)
Antti Haapala
sumber
2
Hanya ada perbedaan yang cukup besar di sini karena (a) string tersebut murni ASCII, artinya penyimpanan internal sudah merupakan versi UTF-8, jadi mencari codec hampir satu-satunya biaya yang terlibat sama sekali, dan (b) string tersebut kecil , jadi bahkan jika Anda memang harus menyandikan, itu tidak akan membuat banyak perbedaan. Cobalah, katakan '\u00012345'*10000,. Keduanya mengambil 28.8us di laptop saya; 50ns tambahan mungkin hilang dalam kesalahan pembulatan. Tentu saja ini adalah contoh yang cukup ekstrem — tetapi 'abc'sama ekstrimnya dengan arah yang berlawanan.
abarnert
@abarnert benar, tetapi meskipun demikian, tidak ada alasan untuk meneruskan argumen sebagai string.
Antti Haapala
Menurut ini, argumen default selalu "benar-benar cara terbaik" untuk melakukan sesuatu, bukan? Analisis kecepatan semacam ini akan terasa seperti kemungkinan besar dilebih-lebihkan jika ini tentang membahas kode C. Dalam bahasa yang ditafsirkan, itu membuat saya tak bisa berkata-kata.
hmijail meratapi orang-orang yang mengundurkan diri