14. Chuỗi, byte và Unicode
14. Chuỗi, byte và Unicode
Dữ liệu văn bản và nhị phân là các họ đối tượng riêng biệt trong Python.strđại diện cho văn bản Unicode.bytesđại diện cho dữ liệu nhị phân bất biến.bytearrayđại diện cho dữ liệu nhị phân có thể thay đổi.
Sự tách biệt này là một trong những lựa chọn thiết kế thời gian chạy quan trọng nhất của Python 3. Văn bản có các ký tự và mã hóa. Dữ liệu nhị phân có byte. CPython triển khai các khái niệm này với các bố cục đối tượng, API và bất biến khác nhau.
14.1 Văn bản và Dữ liệu nhị phân
Một chuỗi là văn bản:python id="ly45du" s = "hello" Đối tượng byte là dữ liệu nhị phân:python id="1wh8hi" b = b"hello" Chúng có thể trông giống nhau đối với nội dung ASCII nhưng chúng thuộc các loại khác nhau.python id="iqtxra" print(type("hello")) # <class 'str'> print(type(b"hello")) # <class 'bytes'> Python không ngầm trộn lẫn chúng:python id="8bzmko" "hello" + b"world" # TypeError Đây là cố ý. Việc kết hợp văn bản và byte yêu cầu quyết định mã hóa.```python id="8w5t7o"
text = "hello"
data = text.encode("utf-8")
again = data.decode("utf-8")
## 14.2`str`Đại diện cho văn bản Unicode
một con trăn`str`là một chuỗi các điểm mã Unicode.```python id="tq2xfz"
s = "Python 🐍"
print(len(s))
len(s)đếm điểm mã, không mã hóa byte.```python id="lxgm2u"
s = "é"
print(len(s)) # 1 print(len(s.encode("utf-8"))) # 2
Sự khác biệt này xuất hiện xuyên suốt nội bộ CPython:```text id="c3cd4w"
str
logical Unicode text
bytes
encoded or arbitrary binary data
```## 14.3 Điểm mã Unicode
Điểm mã Unicode là một giá trị nguyên được gán theo tiêu chuẩn Unicode.
Ví dụ:
| Nhân vật | Điểm mã |
| --------- | ---------- |
|`A` | `U+0041` |
| `é` | `U+00E9` |
| `中` | `U+4E2D` |
| `🐍` | `U+1F40D`|
Python phơi bày điều này thông qua`ord`Và`chr`.
```python id="cvt38d"
print(ord("A")) # 65
print(hex(ord("🐍"))) # 0x1f40d
print(chr(0x1f40d)) # 🐍
```Một chuỗi không được lưu trữ dưới dạng byte UTF-8 bên trong theo nghĩa phổ quát đơn giản. CPython chọn bố cục bên trong được tối ưu hóa cho nội dung của chuỗi.
## 14.4 Biểu diễn chuỗi linh hoạt
CPython sử dụng cách biểu diễn nội bộ linh hoạt cho chuỗi Unicode.
Ý tưởng chính rất đơn giản:```text id="hj5qoo"
Use the smallest fixed-width storage that can represent every code point in the string.
```Về mặt khái niệm:
| Điểm mã tối đa trong chuỗi | Chiều rộng lưu trữ |
| ---------------------------- | --------------------: |
| chỉ ASCII | 1 byte mỗi ký tự |
| Lên đến`U+00FF`| 1 byte mỗi ký tự |
| Lên đến`U+FFFF`| 2 byte mỗi ký tự |
| Bên trên`U+FFFF`| 4 byte mỗi ký tự |
Ví dụ:```python id="k8wqod"
"abc" # compact ASCII path
"café" # may fit in 1-byte storage
"中" # needs 2-byte storage
"🐍" # needs 4-byte storage
```Thiết kế này tránh lãng phí bốn byte cho mỗi ký tự đối với văn bản nặng ASCII thông thường trong khi vẫn hỗ trợ tất cả các điểm mã Unicode.
## 14.5 Siêu dữ liệu đối tượng chuỗi
Chuỗi CPython không chỉ lưu trữ dữ liệu ký tự.
Các lĩnh vực khái niệm bao gồm:```text id="xr6949"
object header
length
hash cache
state flags
kind
compact flag
ASCII flag
ready flag
character data
optional UTF-8 cache
```Bố cục C chính xác là dành riêng cho từng phiên bản, nhưng các bất biến quan trọng hơn tên trường.
Siêu dữ liệu quan trọng:
| Siêu dữ liệu | Mục đích |
| ------------ | --------------------------------------------- |
| Chiều dài | Số điểm mã Unicode |
| Bộ nhớ đệm băm | Lưu trữ hàm băm sau lần tính toán đầu tiên |
| Loại | Chiều rộng lưu trữ |
| Cờ ASCII | Đường dẫn nhanh cho chuỗi ASCII |
| Cờ nhỏ gọn | Liệu dữ liệu có được lưu trữ gần tiêu đề đối tượng hay không |
| Bộ đệm UTF-8 | Biểu mẫu được mã hóa trong bộ nhớ đệm để sử dụng API C |
Chuỗi không thể thay đổi nên siêu dữ liệu được lưu trong bộ nhớ đệm sẽ an toàn. Sau khi tính toán, hàm băm vẫn hợp lệ.
## 14.6 Tính bất biến của chuỗi
Chuỗi Python là bất biến.```python id="8lnw2h"
s = "hello"
s[0] = "H" # TypeError
```Các thao tác tạo chuỗi mới:```python id="q4ux6e"
s = "hello"
t = "H" + s[1:]
print(s) # hello
print(t) # Hello
```Tính bất biến mang lại cho CPython một số lợi thế:```text id="ylorrg"
hash values can be cached
strings can be safely interned
strings can be shared across dictionaries
strings can be used as dict keys
substring operations cannot mutate originals
```Cái giá phải trả là việc nối chuỗi lặp đi lặp lại có thể phân bổ nhiều chuỗi trung gian nếu được viết kém.
## 14.7 Băm chuỗi
Chuỗi có thể băm được.```python id="7pmw4s"
hash("name")
```Hàm băm của chuỗi được tính từ nội dung của nó. Vì các chuỗi là bất biến nên CPython có thể lưu trữ kết quả bên trong đối tượng chuỗi.
Điều này quan trọng vì các chuỗi được sử dụng nhiều làm khóa từ điển:```text id="n69066"
module globals
object attribute names
class dictionaries
keyword argument names
JSON-like data
configuration maps
protocol field names
```Nếu không có hàm băm chuỗi được lưu trong bộ nhớ đệm, việc tra cứu thuộc tính và tra cứu từ điển sẽ tốn kém hơn.
## 14.8 Thực tập chuỗi
Thực tập có nghĩa là sử dụng lại một đối tượng chuỗi cho các giá trị chuỗi bằng nhau trong các trường hợp đã chọn.```python id="alsrhm"
a = "identifier"
b = "identifier"
print(a is b) # may be True
```CPython thực hiện nhiều chuỗi giống như mã định danh vì chúng phổ biến trong tra cứu thuộc tính và không gian tên.
Thực tập rất hữu ích cho:```text id="te68vu"
attribute names
variable names
keyword names
module names
common internal strings
```Với các chuỗi nội bộ, kiểm tra đẳng thức thường có thể trở thành kiểm tra con trỏ sau kiểm tra hàm băm trong các đường dẫn bên trong.
Nhưng mã người dùng không nên phụ thuộc vào nhận dạng chuỗi tùy ý.
Chính xác:```python id="k4ah3b"
if a == b:
...
```Không đúng:```python id="tgxz95"
if a is b:
...
```Sử dụng`is`chỉ dành cho ngữ nghĩa nhận dạng, đặc biệt là các tài liệu đơn lẻ như`None`.
## 14.9 Mã hóa
Mã hóa chuyển đổi văn bản thành byte.```python id="n587av"
s = "café"
b = s.encode("utf-8")
print(b) # b'caf\xc3\xa9'
```Chuỗi là văn bản Unicode. UTF-8 là một biểu diễn byte bên ngoài.
Các mã hóa phổ biến:
| Mã hóa | Sử dụng |
| -------- | ----------------------------------- |
| UTF-8 | Web, tệp, API, hệ thống Unix |
| UTF-16 | Một số API nền tảng và định dạng tệp |
| UTF-32 | Bộ nhớ Unicode có chiều rộng cố định |
| Tiếng Latinh-1 | Ánh xạ byte phương Tây kế thừa |
| ASCII | Tập hợp con tiếng Anh 7-bit |
CPython không coi mã hóa là thuộc tính của`str`. Một chuỗi được giải mã văn bản. Mã hóa được sử dụng khi vượt qua ranh giới byte.
Giải mã ## 14.10
Giải mã chuyển đổi byte thành văn bản.```python id="n1sd4m"
b = b"caf\xc3\xa9"
s = b.decode("utf-8")
print(s) # café
```Nếu các byte không hợp lệ đối với mã hóa đã chọn thì việc giải mã sẽ không thành công trừ khi sử dụng trình xử lý lỗi.```python id="83jkr9"
b = b"\xff"
b.decode("utf-8") # UnicodeDecodeError
b.decode("utf-8", errors="ignore")
b.decode("utf-8", errors="replace")
```Trình xử lý lỗi bao gồm:```text id="j4u46t"
strict
ignore
replace
backslashreplace
surrogateescape
surrogatepass
```Lỗi mã hóa là một phần của ranh giới văn bản, không phải các thao tác chuỗi thông thường.
## 14.11 Ranh giới UTF-8
Hầu hết văn bản bên ngoài hiện đại là UTF-8.
Ví dụ:```text id="ps2rks"
source files
JSON
HTTP payloads
HTML
Markdown
logs
configuration files
database text protocols
```Một quy tắc thực tế:```text id="cszoaq"
inside Python
use str
at file, network, process, and binary protocol boundaries
encode or decode explicitly
```Ví dụ:```python id="le5dmj"
from pathlib import Path
text = Path("notes.txt").read_text(encoding="utf-8")
data = text.encode("utf-8")
```Điều này giữ cho ranh giới rõ ràng.
## 14.12 Mã hóa mã nguồn
Các tệp nguồn Python được giải mã trước khi phân tích cú pháp.
Mã hóa nguồn mặc định là UTF-8 trừ khi khai báo mã hóa có quy định khác.
Ví dụ:```python id="cndzxu"
# -*- coding: utf-8 -*-
name = "café"
```Trình mã thông báo hoạt động trên văn bản nguồn được giải mã. Chuỗi ký tự sau đó trở thành Python`str`các đối tượng trừ khi chúng là byte bằng chữ.```python id="wu9nv8"
s = "abc" # str
b = b"abc" # bytes
```Sự khác biệt này được thực hiện trong quá trình phân tích cú pháp và biên dịch.
## 14.13 Chuỗi ký tự
Python có một số dạng chuỗi ký tự.```python id="9uk2iv"
"hello"
'hello'
"""hello"""
'''hello'''
r"\n"
f"value = {x}"
```Tiền tố chữ ảnh hưởng đến việc phân tích cú pháp:
| Tiền tố | Ý nghĩa |
| ------------ | ------------------------------- |
|`r`| Chuỗi ký tự thô |
|`f`| Chuỗi ký tự được định dạng |
|`b`| Byte theo nghĩa đen |
|`u`| Tiền tố tương thích lịch sử |
| kết hợp |`fr`, `rf`, `br`, `rb`|
Một chuỗi thô thay đổi cách trình phân tích cú pháp giải thích các ký tự thoát.```python id="5il9aw"
s = r"\n"
print(s) # \n
```Nó vẫn tạo bình thường`str`.
## Đối tượng 14,14 byte`bytes`đại diện cho dữ liệu nhị phân bất biến.```python id="rdc547"
b = b"hello"
```Đối tượng byte là một chuỗi các số nguyên trong phạm vi từ 0 đến 255.```python id="a55532"
b = b"ABC"
print(b[0]) # 65
print(b[1]) # 66
```Cắt lát trả về một đối tượng byte khác:```python id="ry5nl7"
print(b[1:]) # b'BC'
```Bởi vì`bytes`là bất biến, nó có thể băm được.```python id="524c01"
d = {b"key": "value"}
```Byte rất hữu ích cho:```text id="ujfy6z"
network protocols
binary files
cryptographic data
compressed data
encoded text
database wire formats
image and audio formats
```## Bố cục đối tượng 14,15 byte
Đối tượng byte có kích thước thay đổi.
Về mặt khái niệm:```text id="kr49t3"
PyBytesObject
PyVarObject header
ob_size = number of bytes
hash cache
byte data
trailing NUL byte for C compatibility
```Byte NUL ở cuối giúp ích khi truyền dữ liệu tới các API C có chuỗi C, nhưng byte có thể chứa byte NUL được nhúng:```python id="z96jr9"
b = b"a\0b"
print(len(b)) # 3
```Vì vậy, byte không được coi là chuỗi kết thúc bằng NUL thông thường trừ khi API đặc biệt cho phép điều đó và nội dung được xác định là an toàn.
## 14.16 Đối tượng Bytearray`bytearray`là dữ liệu nhị phân có thể thay đổi.```python id="cltuuo"
buf = bytearray(b"hello")
buf[0] = ord("H")
print(buf) # bytearray(b'Hello')
```Một bytearray hỗ trợ sửa đổi tại chỗ:```python id="vf2c2m"
buf.append(33)
buf.extend(b" world")
```Nó không thể băm được vì nội dung của nó có thể thay đổi.```python id="2mamf7"
hash(bytearray(b"abc")) # TypeError
```Về mặt khái niệm, bytearray gần giống với danh sách byte có thể thay đổi hơn, nhưng được triển khai dưới dạng bộ đệm byte nhỏ gọn hơn là một mảng tham chiếu đối tượng số nguyên Python.
## 14,17 Byte so với Danh sách Int
So sánh:```python id="mm43w3"
b = b"abc"
xs = [97, 98, 99]
```Đối tượng bytes lưu trữ byte thô một cách gọn gàng.
Danh sách lưu trữ các tham chiếu đến các đối tượng số nguyên Python.
Về mặt khái niệm:```text id="6zghb9"
bytes
[97][98][99]
list
[ptr][ptr][ptr]
| | |
v v v
int int int
```Đối với dữ liệu nhị phân,`bytes`Và`bytearray`bộ nhớ hiệu quả hơn nhiều.
## 14.18 Chế độ xem bộ nhớ`memoryview`hiển thị bộ đệm của đối tượng khác.```python id="lk88r7"
buf = bytearray(b"hello")
view = memoryview(buf)
view[0] = ord("H")
print(buf) # bytearray(b'Hello')
```Chế độ xem bộ nhớ tránh sao chép.
Nó rất hữu ích khi cắt hoặc truyền dữ liệu nhị phân giữa các API:```python id="fmmfbg"
data = bytearray(b"abcdef")
view = memoryview(data)[2:5]
print(view.tobytes()) # b'cde'
```Chế độ xem giữ cho nhà xuất khẩu tồn tại và thực thi các quy tắc trọn đời của bộ đệm.
## 14.19 Giao thức bộ đệm
Giao thức đệm là giao thức cấp C đằng sau`memoryview`.
Nó cho phép các đối tượng hiển thị bộ nhớ thô cho các đối tượng khác.
Các nhà xuất khẩu đệm phổ biến:```text id="yt656l"
bytes
bytearray
array.array
memoryview
mmap
third-party arrays such as NumPy arrays
custom extension objects
```Giao thức mô tả:```text id="va15hu"
pointer to memory
length
item size
format
number of dimensions
shape
strides
readonly flag
lifetime callbacks
```Điều này làm cho việc xử lý nhị phân không sao chép có thể thực hiện được.
## 14.20 I/O văn bản và I/O nhị phân
Tập tin có thể được mở ở chế độ văn bản hoặc chế độ nhị phân.
Chế độ văn bản giải mã byte thành chuỗi:```python id="ztfr4f"
with open("notes.txt", "r", encoding="utf-8") as f:
text = f.read()
```Chế độ nhị phân trả về byte:```python id="2vcxb8"
with open("notes.txt", "rb") as f:
data = f.read()
```Chế độ văn bản xử lý mã hóa, giải mã và dịch dòng mới.
Chế độ nhị phân cung cấp byte thô.
Chọn dựa trên mô hình dữ liệu:```text id="ifzmcj"
human-readable text
text mode, str
protocol bytes or exact file bytes
binary mode, bytes
```## 14.21 Lỗi ranh giới phổ biến
Một lỗi phổ biến là trộn văn bản và byte ở ranh giới.
Không đúng:```python id="zctul0"
def send(sock, message):
sock.sendall(message) # fails if message is str
```Chính xác:```python id="daxwma"
def send(sock, message):
data = message.encode("utf-8")
sock.sendall(data)
```Để nhận:```python id="jynmly"
data = sock.recv(4096)
text = data.decode("utf-8")
```Giữ chuyển đổi rõ ràng để mã hóa hiển thị.
## 14.22 Nối chuỗi
Chuỗi là bất biến nên việc nối chuỗi sẽ tạo ra một chuỗi mới.```python id="fnu5rd"
s = "a"
s = s + "b"
s = s + "c"
```Điều này có thể phân bổ nhiều lần.
Đối với nhiều phần, thích`join`:
```python id="xnzlkg"
parts = ["a", "b", "c"]
s = "".join(parts)
```Để truyền phát văn bản, hãy sử dụng`io.StringIO`:
```python id="1icewe"
from io import StringIO
buf = StringIO()
buf.write("a")
buf.write("b")
buf.write("c")
s = buf.getvalue()
```CPython có các tối ưu hóa cho một số trường hợp nối cục bộ, nhưng mã không nên phụ thuộc vào chúng để có hiệu suất chung.
## Tòa nhà 14,23 byte
Byte cũng không thay đổi được.
Việc nối các byte lặp đi lặp lại có cùng một vấn đề về phân bổ.```python id="bufv11"
data = b""
for chunk in chunks:
data += chunk
```Tốt hơn:```python id="5ojx6g"
data = b"".join(chunks)
```Đối với xây dựng gia tăng có thể thay đổi:```python id="bpfowr"
buf = bytearray()
for chunk in chunks:
buf.extend(chunk)
data = bytes(buf)
```Đối với việc xây dựng nhị phân giống như tập tin:```python id="s6mtb3"
from io import BytesIO
buf = BytesIO()
buf.write(b"abc")
buf.write(b"def")
data = buf.getvalue()
```## 14.24 Chuẩn hóa Unicode
Các chuỗi Unicode khác nhau có thể trông giống nhau.
Ví dụ:```python id="d3pxs7"
a = "é" # single code point U+00E9
b = "e\u0301" # e plus combining acute accent
print(a == b) # False
```Chúng có thể hiển thị tương tự nhau, nhưng chúng là các chuỗi điểm mã khác nhau.
Bình thường hóa khi so sánh văn bản của con người:```python id="7m77tv"
import unicodedata
a = unicodedata.normalize("NFC", a)
b = unicodedata.normalize("NFC", b)
print(a == b) # True
```Các hình thức chuẩn hóa phổ biến:
| Mẫu | Ý nghĩa |
| ---- | ----------------------------- |
| NFC | Thành phần kinh điển |
| NFD | Phân hủy kinh điển |
| NFKC | Thành phần tương thích |
| NFKD | Phân hủy khả năng tương thích |
Chuẩn hóa là mối quan tâm ở cấp độ Unicode, không phải là mối quan tâm về bố cục đối tượng CPython. Nhưng nó quan trọng để xử lý văn bản chính xác.
## 14.25 Trường hợp gấp
So sánh không phân biệt chữ hoa chữ thường nên sử dụng`casefold`, không`lower`.
```python id="xo53gl"
a = "Straße"
b = "strasse"
print(a.lower() == b.lower()) # often False
print(a.casefold() == b.casefold()) # True
casefoldđược thiết kế để kết hợp không phân biệt chữ hoa chữ thường.
Đối với mã định danh, tên tệp, tên người dùng và trường giao thức, hãy xác định quy tắc chuẩn hóa và viết hoa chính xác. Đừng đoán.
14.26 Cụm đồ thị
Một ký tự mà người dùng nhìn thấy có thể chứa nhiều điểm mã.
Ví dụ:```python id="g55aom" s = "👨👩👧👦" print(len(s))
Python`str`lập chỉ mục các điểm mã, không phải cụm biểu đồ.```python id="1i0lb4"
s[0]
```có thể chỉ trả về một phần của ký tự hiển thị.
Để chỉnh sửa văn bản giao diện người dùng, di chuyển con trỏ, cắt ngắn và chiều rộng hiển thị, việc lập chỉ mục điểm mã có thể không đủ. Bạn cần phân đoạn đồ thị nhận biết Unicode.
## 14.27 Chiến lược lỗi mã hóa
Mã hóa có thể thất bại nếu một ký tự không thể được biểu diễn.```python id="j37zya"
"é".encode("ascii") # UnicodeEncodeError
```Chiến lược lỗi kiểm soát hành vi:```python id="9s35v1"
"é".encode("ascii", errors="ignore")
"é".encode("ascii", errors="replace")
"é".encode("ascii", errors="backslashreplace")
```Đối với ranh giới tệp và quy trình, hãy chọn cách xử lý lỗi có chủ ý.
Một chiến lược hướng tới Unix phổ biến là`surrogateescape`, cho phép các byte không thể giải mã được thực hiện chuyến đi khứ hồi`str`không mất dữ liệu trong một số bối cảnh hệ thống tập tin và môi trường.
## 14.28 Mã hóa hệ thống tập tin
Đường dẫn tệp vượt qua ranh giới văn bản và byte.
Python thường hiển thị các đường dẫn dưới dạng`str`, nhưng hệ điều hành thường hoạt động trên các chuỗi byte được mã hóa hoặc các định dạng chuỗi gốc của nền tảng.
CPython có logic mã hóa hệ thống tệp để chuyển đổi giữa các chuỗi Python và biểu diễn đường dẫn nền tảng.
Quy tắc thực tế:```text id="pqbj4c"
use pathlib and str paths for normal application code
use bytes paths only when you need exact low-level byte behavior
```Ví dụ:```python id="w0jnqu"
from pathlib import Path
p = Path("data") / "notes.txt"
text = p.read_text(encoding="utf-8")
```## 14.29 Chế độ xem API C của Unicode
Mã mở rộng C thường cần chấp nhận hoặc tạo chuỗi.
Các hoạt động phổ biến bao gồm:```text id="psub45"
create Unicode from UTF-8
convert Unicode to UTF-8
inspect length
read code points
parse arguments as str
```Ví dụ về khái niệm:```c id="ffcssi"
PyObject *s = PyUnicode_FromString("hello");
```Và:```c id="umgbtx"
const char *p = PyUnicode_AsUTF8(obj);
```Con trỏ UTF-8 được một số API trả về có thể trỏ vào bộ đệm do đối tượng chuỗi sở hữu. Tuổi thọ của nó phụ thuộc vào đối tượng sở hữu còn sống.
Mã mở rộng không được giải phóng con trỏ đó.
## 14.30 Chế độ xem byte của API C
Byte hiển thị bộ nhớ nhị phân liền kề.
Ví dụ về khái niệm:```c id="g34cn9"
PyObject *b = PyBytes_FromStringAndSize(data, len);
```Truy cập:```c id="q3e1ai"
char *p = PyBytes_AS_STRING(b);
Py_ssize_t n = PyBytes_GET_SIZE(b);
```Các macro nhanh giả sử đối tượng thực sự là một đối tượng byte.
API được kiểm tra an toàn hơn nên được sử dụng ở các ranh giới công cộng.
Byte có thể chứa byte NUL, vì vậy hãy luôn sử dụng độ dài rõ ràng.
## 14.31 Chọn đúng loại
| Cần | Loại |
| ------------------------- | ----------------------------- |
| Văn bản con người |`str`|
| Văn bản được mã hóa |`bytes`|
| Dữ liệu giao thức nhị phân |`bytes`|
| Bộ đệm nhị phân có thể thay đổi |`bytearray`|
| Chế độ xem không sao chép |`memoryview`|
| Nhiều đoạn văn bản |`list[str]`cộng thêm`"".join`|
| Nhiều đoạn nhị phân |`list[bytes]`cộng thêm`b"".join`|
| Người viết văn bản gia tăng |`io.StringIO`|
| Nhà văn nhị phân gia tăng |`io.BytesIO`hoặc`bytearray`|
Loại sẽ phản ánh mô hình dữ liệu. Tránh sử dụng`str`cho các byte tùy ý. Tránh sử dụng`bytes`cho văn bản được giải mã.
## 14.32 Mô hình tinh thần
Sử dụng mô hình này:```text id="dluupp"
str
immutable Unicode code point sequence
optimized internal storage
cached hash
explicit encode/decode boundary
bytes
immutable byte sequence
compact binary storage
hashable
no text semantics unless decoded
bytearray
mutable byte sequence
compact binary storage
useful for incremental construction
memoryview
zero-copy view over buffer-exporting object
lifetime tied to exporter
```Lỗi xử lý văn bản thường đến từ các điểm mã, byte, mã hóa, cụm biểu đồ, chuẩn hóa và độ rộng hiển thị khó hiểu. Mô hình đối tượng của CPython giữ văn bản và byte riêng biệt để các quyết định này vẫn rõ ràng.
## 14.33 Tóm tắt`str`là đối tượng văn bản Unicode của CPython. Nó không thể thay đổi, có thể băm và được tối ưu hóa nội bộ thông qua bộ nhớ linh hoạt, hàm băm được lưu trong bộ nhớ đệm và thực tập. Nó đại diện cho văn bản được giải mã, không phải byte được mã hóa.`bytes`là dữ liệu nhị phân bất biến.`bytearray`là dữ liệu nhị phân có thể thay đổi.`memoryview`cung cấp quyền truy cập không sao chép vào các đối tượng xuất bộ đệm.
Ranh giới giữa văn bản và dữ liệu nhị phân rất rõ ràng: mã hóa`str`để sản xuất`bytes`, và giải mã`bytes`để sản xuất`str`. Ranh giới này rất cần thiết cho I/O tệp chính xác, giao thức mạng, giải mã nguồn, mã mở rộng và các ứng dụng nhận biết Unicode.