2.6. Teks vs bytes¶
Python memiliki dua tipe urutan untuk data karakter mentah:
str-- urutan codepoint Unicode. Digunakan untuk semua teks yang dapat dibaca manusia: jalur file, pesan log, payload JSON.bytes-- urutan bilangan bulat dalam rentang 0 -- 255. Digunakan untuk data biner mentah: bingkai UART, buffer citra, paket jaringan, nilai register.
Keduanya tidak dapat dicampur tanpa konversi eksplisit. Meneruskan str ke metode write perangkat keras akan memunculkan TypeError, dan sebaliknya juga ditolak.
Sebuah str menyimpan karakter Unicode; sebuah bytes menyimpan oktet mentah. Berpindah di antara keduanya disebut encoding (str → bytes) dan decoding (bytes → str).¶
2.6.1. Literal bytes¶
Literal bytes adalah literal seperti string yang diawali dengan b:
header = b"OMV"
crlf = b"\r\n"
payload = b"\x01\x02\x03"
Hanya karakter ASCII yang diizinkan langsung di dalam literal bytes; nilai non-ASCII harus ditulis sebagai escape hex \xHH.
2.6.2. Encoding dan decoding¶
str.encode()mengonversi string ke bytes menggunakan encoding yang bernama (default"utf-8").bytes.decode()melakukan kebalikannya.
>>> "hello".encode()
b'hello'
>>> "héllo".encode()
b'h\xc3\xa9llo' # é is two bytes in UTF-8
>>> b"hello".decode()
'hello'
UTF-8 adalah default dan pilihan yang tepat untuk segala sesuatu yang mungkin mengandung karakter non-ASCII. Gunakan "ascii" hanya ketika data dijamin berupa ASCII biasa; dengan cara itu byte non-ASCII yang terselip akan memunculkan UnicodeError alih-alih lewat secara diam-diam.
2.6.3. Pengindeksan dan pemotongan¶
Nilai bytes berperilaku seperti urutan bilangan bulat saat diindeks, bukan urutan string satu byte:
>>> data = b"abc"
>>> data[0]
97 # the int 97, not 'a'
>>> data[0:1]
b'a' # slicing returns bytes
Kesalahan umum adalah membandingkan data[0] == "a" dan terkejut karena hasilnya False -- data[0] adalah bilangan bulat, bukan string satu karakter, sehingga kedua nilai tersebut tidak pernah dapat cocok.
2.6.4. ord dan chr -- menjembatani karakter dan bilangan bulat¶
Karena pengindeksan bytes mengembalikan bilangan bulat tetapi sisa program kemungkinan berpikir dalam karakter, Python menyediakan dua fungsi bawaan untuk berpindah di antara keduanya:
ord()-- mengambil string satu karakter dan mengembalikan codepoint bilangan bulatnya.chr()-- kebalikannya: diberikan bilangan bulat, mengembalikan string satu karakter untuk codepoint tersebut.
>>> ord("a")
97
>>> chr(97)
'a'
>>> ord("A"), chr(0x41)
(65, 'A')
Untuk karakter ASCII, codepoint sama dengan nilai byte, sehingga ord("a") dan b"a"[0] keduanya menghasilkan 97. Hal ini membuat perbandingan byte dapat dibaca dalam hal karakter yang sebenarnya Anda pedulikan:
>>> data = b"abc"
>>> data[0] == ord("a") # instead of the magic number 97
True
Dan chr() berguna untuk pencatatan atau debugging ketika Anda ingin melihat bentuk yang dapat dicetak dari sebuah byte:
>>> chr(data[0])
'a'
Untuk karakter non-ASCII, ord() mengembalikan codepoint Unicode, yang tidak sama dengan satu byte pun dalam bentuk yang dikodekan; representasi byte bergantung pada encoding.
2.6.5. bytearray untuk buffer yang dapat diubah¶
bytes bersifat immutable -- setiap "modifikasi" mengembalikan objek baru dan membiarkan yang asli tidak berubah. Untuk data yang ingin Anda modifikasi, tambahkan, atau isi bagian demi bagian, gunakan bytearray. Ia menyimpan konten yang sama dengan bytes tetapi mendukung mutasi di tempat:
>>> s = b"hello"
>>> s[0] = ord("H")
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'bytes' object does not support item assignment
>>> s = bytearray(b"hello")
>>> s[0] = ord("H")
>>> s
bytearray(b'Hello')
2.6.5.1. Membuat bytearray¶
Konstruktor bytearray menerima beberapa input:
bytearray(8)-- buffer berisi 8 byte nol.bytearray(b"hello")-- salinan yang dapat diubah dari nilai bytes.bytearray("hello", "utf-8")-- sebuah bytearray dari string, menggunakan encoding yang diberikan.bytearray([72, 73, 74])-- sebuah bytearray dari urutan bilangan bulat dalam rentang 0 -- 255 (di sini,b"HIJ").
>>> bytearray(4)
bytearray(b'\x00\x00\x00\x00')
>>> bytearray(b"abc")
bytearray(b'abc')
>>> bytearray("café", "utf-8")
bytearray(b'caf\xc3\xa9')
2.6.5.2. Memodifikasi bytearray¶
Penugasan berdasarkan indeks dan slice bekerja seperti list:
>>> buf = bytearray(8) # 8 zero bytes
>>> buf[0] = 0xFF # one byte at a time
>>> buf[1:4] = b"ABC" # replace a slice
>>> buf
bytearray(b'\xffABC\x00\x00\x00\x00')
Setiap byte harus berupa bilangan bulat dalam rentang 0 -- 255; menetapkan tipe lain akan memunculkan TypeError atau ValueError.
Penugasan slice dapat mengubah panjang buffer. Mengganti slice dengan nilai yang lebih panjang akan memperbesar bytearray; mengganti dengan nilai yang lebih pendek akan memperkecilnya. Mengganti dengan b"" menghapus slice sepenuhnya:
>>> buf = bytearray(b"abcdef")
>>> buf[1:3] = b"XYZ" # 2 bytes replaced with 3
>>> buf
bytearray(b'aXYZdef')
>>> buf[1:4] = b"" # delete the inserted run
>>> buf
bytearray(b'adef')
Metode bytearray.append() dan bytearray.extend() menambahkan byte di akhir tanpa mengalokasikan ulang seluruh buffer setiap kali:
>>> buf = bytearray()
>>> buf.append(0x01)
>>> buf.extend(b"abc")
>>> buf
bytearray(b'\x01abc')
2.6.5.3. Membaca dari bytearray¶
Pengindeksan, pemotongan, iterasi, dan metode inspeksi bytes (bytes.startswith(), bytes.find(), bytes.strip(), dll.) semuanya bekerja sama seperti pada nilai bytes. Pengindeksan mengembalikan bilangan bulat; pemotongan mengembalikan bytearray lain:
>>> buf = bytearray(b"OpenMV")
>>> buf[0]
79
>>> buf[0:4]
bytearray(b'Open')
>>> buf.startswith(b"Open")
True
2.6.5.4. Mengonversi antara bytes dan bytearray¶
bytes dan bytearray saling mengonversi dengan konstruktornya. Gunakan ini ketika sebuah API membutuhkan satu bentuk secara khusus:
>>> ba = bytearray(b"hello")
>>> snapshot = bytes(ba) # immutable copy
>>> ba[0] = ord("H")
>>> ba, snapshot
(bytearray(b'Hello'), b'hello')
2.6.5.5. memoryview untuk pemotongan tanpa salinan¶
Memotong bytes atau bytearray biasanya menyalin byte ke buffer baru. memoryview mengekspos byte yang sama tanpa menyalinnya:
>>> buf = bytearray(b"OpenMV Cam")
>>> view = memoryview(buf)
>>> view[0:6] # shares storage with buf
<memoryview ...>
>>> bytes(view[0:6]) # materialise as bytes when needed
b'OpenMV'
Tampilan atas bytearray juga dapat ditulis -- mengubah tampilan berarti mengubah buffer yang mendasarinya:
>>> view[0] = ord("o")
>>> buf
bytearray(b'openMV Cam')
Gunakan memoryview ketika menyalin slice akan boros -- biasanya ketika buffer besar yang sama diteruskan atau diproses bagian demi bagian. Untuk pekerjaan gaya string sehari-hari pada bytes kecil, pemotongan biasa sudah cukup.