Python 了解 bytes 与 str 的区别
Posted 传说三哥
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python 了解 bytes 与 str 的区别相关的知识,希望对你有一定的参考价值。
Python 有两种类型可以表示字符序列
- bytes:实例包含的是原始数据,即 8 位的无符号值(通常按照 ASCII 编码标准来显示)
- str:实例包含的是 Unicode 码点(code point,也叫作代码点),这些码点与人类语言之中的文本字符相对应
a = bh\\x6511o
print(list(a))
print(a)
a = a\\\\u300 propos
print(list(a))
print(a)
# 输出结果
[104, 101, 49, 49, 111]
bhe11o
[a, \\\\, u, 3, 0, 0, , p, r, o, p, o, s]
a\\u300 propos
Unicode 数据和二进制数据转换
- 把 Unicode 数据转换成二进制数据,必须调用 str 的 encode 方法(编码)
- 把二进制数据转换成 Unicode 数据,必须调用 bytes 的 decode 方法(解码)
- 调用这些方法时,可以明确指出字符集编码,也可以采用系统默认的方案,通常是 UTF-8
使用原始的 8 位值与 Unicode 字符串时需要注意的两个问题
该问题等价于:使用 bytes 和 str 时需要注意的两个问题
问题一:bytes 和 str 的实例互不兼容
使用 + 操作符
# bytes+bytes
print(ba + b1)
# str+str
print(b + 2)
# 输出结果
ba1
b2
- bytes + bytes,str + str 都是允许的
- 但 bytes + str 会报错
# bytes+str
print(c + b2)
# 输出结果
print(c + b2)
TypeError: can only concatenate str (not "bytes") to str
同类型之间也可以用二元操作符来比较大小
assert bc > ba
assert c > a
但 bytes 和 str 之间用二元操作符也会报错
assert bc > a
# 输出结果
assert bc > a
TypeError: > not supported between instances of bytes and str
判断 bytes 与 str 实例是否相等
两个类型的实例相比较总会为 False,即使字符完全相同
# 判断 str、bytes
print(a == ba)
# 输出结果
False
格式化字符串中的 %s
两种类型的实例都可以出现在 % 操作符的右侧,用来替换左侧那个格式字符串(format string)里面的 %s
但是!如果格式字符串是 bytes 类型,那么不能用 str 实例来替换其中的 %s,因为 Python 不知道这个 str 应该按照什么字符集来编码
# %
print(bred %s % blue)
# 输出结果
print(bred %s % blue)
TypeError: %b requires a bytes-like object, or an object that implements __bytes__, not str
但是!反过来却可以,如果格式字符串是 str 类型,则可以用bytes 实例来替换其中的 %s,但结果可能不是预期结果
# %
print(red %s % bblue)
# 输出结果
red bblue
- 这样会让系统在 bytes 实例上面调用 __repr__ 方法
- 调用结果替换格式字符串里的 %s,因此程序会直接输出 bblue,而不是输出 blue
问题二:操作文件句柄时需要使用 Unicode 字符串操作
不能使用原始的 bytes
向文件写入二进制数据会报错
# 写入二进制数据
with open(test.txt, "w+") as f:
f.write(b"\\xf1\\xf2")
# 输出结果
f.write(b"\\xf1\\xf2")
TypeError: write() argument must be str, not bytes
- 报错是因为 w 模式必须以文本模式写入
- 将模式改成 wb 即可正常写入二进制数据
with open(test.txt, "wb") as f:
f.write(b"\\xf1\\xf2")
读取文件中二进制数据
with open(test.txt, "r+") as f:
f.read()
# 输出结果
(result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: utf-8 codec cant decode byte 0xf1 in position 0: invalid continuation byte
- 报错是因为 r 模式必须以文本模式读取
- 以文本模式操纵文件句柄时,系统会采用默认的文本编码方案处理二进制数据
- 所以,上面那种写法会让系统通过 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())
# 输出结果
ñò
以上是关于Python 了解 bytes 与 str 的区别的主要内容,如果未能解决你的问题,请参考以下文章
python2 与python3中最大的区别(编码问题bytes&str