本文主要介绍在 Python
中 bytes
与 str
的区别。1
Updated: 2022 / 6 / 16
bytes 与 str 的区别
1. Python 有两种类型可以表示字符序列
bytes
下面所示实例包含的是原始数据 ,即 8 位的无符号值(通常按照ASCII编码
标准来显示)str
下面所示实例包含的是Unicode
码点(code point
,也叫作代码点),这些码点与人类语言之中的文本字符相对应
a = b'h\x6511o' print(list(a)) # [104, 101, 49, 49, 111] print(a) # b'he11o' a = 'a\\u300 propos' print(list(a)) # ['a', '\\', 'u', '3', '0', '0', ' ', 'p', 'r', 'o', 'p', 'o', 's'] print(a) # a\u300 propos
2. Unicode
数据和二进制数据转换
- 把
Unicode
数据转换成二进制数据,必须调用str
的encode
方法(编码)
FileContent = 'This is file content.'
print(FileContent)
# 'This is file content.'
print(type(FileContent))
# <class 'str'>
FileContent = FileContent.encode(encoding='utf-8')
print(FileContent)
# b'This is file content.'
print(type(FileContent))
# <class 'bytes'>
- 把二进制数据转换成
Unicode
数据,必须调用bytes
的decode
方法(解码)
FileContent = b'This is file content.'
print(FileContent)
# b'This is file content.'
print(type(FileContent))
# <class 'bytes'>
FileContent = FileContent.decode(encoding='utf-8')
print(FileContent)
# 'This is file content.'
print(type(FileContent))
# <class 'str'>
调用这些方法时,可以明确指出字符集编码,也可以采用系统默认的方案,通常是
UTF-8
当前操作系统默认的字符集编码,
Python
一行代码查看当前操作系统默认的编码标准: 在cmd
中执行:python3 -c 'import locale; print(locale.getpreferredencoding())' # UTF-8
3. 使用原始的 8 位值与 Unicode
字符串
使用原始的 8 位值与 Unicode
字符串时需要注意的两个问题 (该问题等价于使用 bytes
和 str
时需要注意的两个问题):
- 3.1
bytes
和str
的互不兼容
使用
+
操作符
# bytes+bytes print(b'a' + b'1') # b'a1' # str+str print('b' + '2') # b2 # bytes+str print('c' + b'2') # TypeError: can only concatenate str (not "bytes") to str
同类型之间也可以用二元操作符来比较大小
# bytes bytes assert b'c' > b'a' assert b'c' < b'a' # AssertionError print(b'a' == b'a') # True # str str assert 'c' > 'a' assert 'c' < 'a' # AssertionError print('a' == 'a') # True # bytes str assert b'c' > 'a' # TypeError: '>' not supported between instances of 'bytes' and 'str' print('a' == b'a') # False
格式化字符串中的
%s
两种类型的实例都可以出现在
%
操作符的右侧,用来替换左侧那个格式字符串(format string
)里面的%s
。但是如果格式字符串是bytes
类型,那么不能用str
实例来替换其中的%s
,因为Python
不知道这个str
应该按照什么字符集来编码。
# bytes % str print(b'red %s' % 'blue' # TypeError: %b requires a bytes-like object, or an object that implements __bytes__, not 'str' # str % bytes print('red %s' % b'blue') # red b'blue' # @ 这样会让系统在 bytes 实例上面调用 __repr__ 方法。调用结果替换格式字符串里的 %s,因此程序会直接输出 b'blue',而不是输出 blue
- 3.2 操作文件句柄时需要使用
Unicode
字符串操作, 不能使用原始的bytes
w
模式必须以 ‘文本’ 模式写入, 否则向文件写入二进制数据会报错:
# 写入二进制数据 with open('test.txt', "w+") as f: f.write(b"\xf1\xf2") # TypeError: write() argument must be str, not bytes
wb
可正常写入二进制数据
# 写入二进制数据 with open('test.txt', "wb") as f: f.write(b"\xf1\xf2")
r
模式必须以 ‘文本’ 模式写入, 否则从文件读取二进制数据会报错:
# 读取二进制数据 with open('test.txt', "r+") as f: f.read() # UnicodeDecodeError: 'utf-8' codec can't decode byte 0xf1 in position 0: invalid continuation byte # @以文本模式操纵文件句柄时,系统会采用 默认的文本编码 方案处理二进制数据。所以,上面那种写法会让系统通过 `bytes.decode` 把这份数据解码成 `str` 字符串,再用 `str.encode` 把字符串编码成二进制值。然而对于大多数系统来说,默认的文本编码方案是 `UTF-8`,所以系统很可能会把 `b'\xf1\xf2\xf3\xf4\xf5'` 当成 `UTF-8` 格式的字符串去解码,于是就会出现上面那样的错误。
rb
可正常读取二进制数据
# 写入二进制数据 with open('test.txt', "rb") as f: print(b"\xf1\xf2" == f.read()) # True
另一种改法,设置
encoding
参数指定字符串编码:
with open('test.txt', "r", encoding="cp1252") as f: print(f.read())
补充说明: