这是一个非常核心且重要的概念,尤其在处理文本、网络请求、文件读写等场景时。

核心概念:Unicode vs. UTF-8
要明白 Unicode 和 UTF-8 是两个不同但紧密相关的东西。
-
Unicode (字符集)
- 是什么:Unicode 就像一个巨大的“字符库”或“字典”,它为世界上几乎所有的字符(比如英文字母 'A'、中文 '中'、表情符号 '😂')都分配了一个唯一的数字,这个数字被称为 码点。
- 表示方式:在 Python 中,码点通常用
U+后跟十六进制数表示,U+0041(A),U+4E2D(中),U+1F602(😂)。 - 在 Python 中的体现:在 Python 3 中,字符串(
str)类型默认就是 Unicode 字符串,当你写s = "你好,世界!"时,变量s就是一个 Unicode 字符串,它内部存储的是这些字符对应的码点。
-
UTF-8 (编码规则)
- 是什么:UTF-8 是一种将 Unicode 码点“转换”或“编码”成计算机可以存储和传输的字节序列的规则,它是 Unicode 最流行的一种实现方式。
- 工作原理:它是一种变长编码,对于英文字符(ASCII 范围内),它使用 1 个字节;对于其他语言的字符(如中文、日文),它通常使用 3 个字节,这使得它非常高效,尤其是在处理大量英文文本时。
- 在 Python 中的体现:
bytes类型是字节序列,当你需要将字符串存入文件、通过网络发送或进行其他二进制操作时,就需要将 Unicode 字符串编码成bytes对象,通常就是使用 UTF-8 编码。
Python 3 中的转换
在 Python 3 中,转换非常直观,主要有两种操作:

Unicode (str) -> UTF-8 (bytes):编码
这个过程也称为 编码,你需要调用字符串的 .encode() 方法,并指定编码格式为 'utf-8'。
# 1. 定义一个 Unicode 字符串 (Python 3 中的 str 类型)
my_string = "你好,世界!Hello, World! 😊"
# 2. 将其编码为 UTF-8 格式的字节序列
my_bytes_utf8 = my_string.encode('utf-8')
# 查看结果
print(f"原始字符串: {my_string}")
print(f"类型: {type(my_string)}")
print("-" * 20)
print(f"编码后的字节序列: {my_bytes_utf8}")
print(f"类型: {type(my_bytes_utf8)}")
# 你可以看到,一个中文字符通常被编码为3个字节,一个英文为1个字节,一个表情符号为4个字节
for char in my_string:
print(f"字符 '{char}' 的 UTF-8 编码: {char.encode('utf-8')}")
输出:
原始字符串: 你好,世界!Hello, World! 😊
类型: <class 'str'>
--------------------
编码后的字节序列: b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c\xef\xbc\x81Hello, World! \xf0\x9f\x98\x8a'
类型: <class 'bytes'>
字符 '你' 的 UTF-8 编码: b'\xe4\xbd\xa0'
字符 '好' 的 UTF-8 编码: b'\xe5\xa5\xbd'
字符 ',' 的 UTF-8 编码: b'\xef\xbc\x8c'
...
字符 '😊' 的 UTF-8 编码: b'\xf0\x9f\x98\x8a'
b'' 的前缀表示这是一个 bytes 对象。
UTF-8 (bytes) -> Unicode (str):解码
这个过程也称为 解码,你需要调用 bytes 对象的 .decode() 方法,并指定编码格式为 'utf-8'。

# 1. 假设我们有一个 UTF-8 编码的字节序列
# (通常从文件、网络等处读取得到)
my_bytes_utf8 = b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c\xef\xbc\x81Hello, World! \xf0\x9f\x98\x8a'
# 2. 将其解码为 Unicode 字符串
my_string_decoded = my_bytes_utf8.decode('utf-8')
# 查看结果
print(f"原始字节序列: {my_bytes_utf8}")
print(f"类型: {type(my_bytes_utf8)}")
print("-" * 20)
print(f"解码后的字符串: {my_string_decoded}")
print(f"类型: {type(my_string_decoded)}")
输出:
原始字节序列: b'\xe4\xbd\xa0\xe5\xa5\xbd\xef\xbc\x8c\xe4\xb8\x96\xe7\x95\x8c\xef\xbc\x81Hello, World! \xf0\x9f\x98\x8a'
类型: <class 'bytes'>
--------------------
解码后的字符串: 你好,世界!Hello, World! 😊
类型: <class 'str'>
实际应用场景
场景1:读写文件
当你用文本模式('r', 'w')打开文件时,Python 会自动帮你处理编码。
-
写入文件 (自动编码)
content = "这是一个测试文件。" with open('test.txt', 'w', encoding='utf-8') as f: f.write(content) # Python 自动将 str 编码为 utf-8 写入文件 -
读取文件 (自动解码)
with open('test.txt', 'r', encoding='utf-8') as f: content = f.read() # Python 自动从文件读取字节流并解码为 str print(content) # 输出: 这是一个测试文件。 print(type(content)) # 输出: <class 'str'>
重要提示:如果文件不是用 UTF-8 编码的,你必须在 open() 函数中指定正确的编码,否则会出现 UnicodeDecodeError,处理 GBK 编码的中文文件:
with open('gbk_file.txt', 'r', encoding='gbk') as f:
场景2:处理网络请求
当你从 API 或网页获取数据时,收到的响应体通常是 bytes 类型,你需要手动解码。
# 这是一个模拟的从网络接收到的字节响应 (requests.get().content)
# 假设服务器返回的是 UTF-8 编码的 JSON
response_bytes = b'{"status": "success", "message": "\u64cd\u4f5c\u6210\u529f\uff01"}' # "操作成功!" 的 UTF-8 编码
# 1. 先解码成字符串
response_str = response_bytes.decode('utf-8')
print(f"解码后的 JSON 字符串: {response_str}")
# 输出: 解码后的 JSON 字符串: {"status": "success", "message": "操作成功!"}
# 2. 然后用 json.loads 解析成 Python 字典
import json
data_dict = json.loads(response_str)
print(f"解析后的字典: {data_dict}")
# 输出: 解析后的字典: {'status': 'success', 'message': '操作成功!'}
常见错误及解决方案
错误1:UnicodeEncodeError
原因:尝试将一个 Unicode 字符串编码成一种它不支持的编码格式,最常见的是试图将非 ASCII 字符(如中文)编码成 'ascii'。
my_string = "你好"
# 这会报错!
# my_string.encode('ascii')
# UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
解决方案:使用一种能够容纳这些字符的编码,如 'utf-8'。
my_string.encode('utf-8') # 正常工作
错误2:UnicodeDecodeError
原因:尝试用错误的编码去解码一个字节序列,一个用 UTF-8 编码的字节序列被错误地用 'ascii' 或 'latin-1' 去解码。
# 这是一个 UTF-8 编码的字节序列
my_bytes_utf8 = "你好".encode('utf-8')
# 尝试用 'ascii' 解码,会报错
# my_bytes_utf8.decode('ascii')
# UnicodeDecodeError: 'ascii' codec can't decode byte 0xe4 in position 0: ordinal not in range(128)
解决方案:找到并使用正确的原始编码,如果不确定 UTF-8,可以尝试 'utf-8-sig'(它会处理 BOM 头),或者用 'latin-1'(它永远不会报错,但可能会解码出乱码,因为它是 1 字符 = 1 字节的映射)。
| 操作 | 方法 | 描述 |
|---|---|---|
| 编码 | my_str.encode('utf-8') |
将 Unicode 字符串 转换为 UTF-8 字节序列 (bytes),用于写入文件、网络传输。 |
| 解码 | my_bytes.decode('utf-8') |
将 UTF-8 字节序列 (bytes) 转换为 Unicode 字符串 (str),用于读取文件、解析网络数据。 |
记住这个核心原则:在 Python 程序内部,统一使用 str (Unicode) 类型处理文本;在与外部世界(文件、网络)交互时,才需要将其编码为 bytes 类型。
