1、Python 有两种类型可以表示字符序列
-
bytes
:实例包含的是 原始数据 ,即 8 位的无符号值(通常按照 ASCII 编码 标准来显示) -
str
:实例包含的是Unicode
码点(code point,也叫作代码点),这些码点与人类语言之中的文本字符相对应
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
a = b 'h\x6511o' print ( list (a)) print (a) a = 'a\\u300 propos' print ( list (a)) print (a) # 输出结果 [ 104 , 101 , 49 , 49 , 111 ] b 'he11o' [ 'a' , '\\', ' u ', ' 3 ', ' 0 ', ' 0 ', ' ', ' p ', ' r ', ' o ', ' p ', ' o ', ' s'] a\u300 propos |
2、Unicode 数据和二进制数据转换
-
把
Unicode
数据转换成二进制数据,必须调用 str 的encode
方法(编码) -
把二进制数据转换成
Unicode
数据,必须调用 bytes 的decode
方法(解码) - 调用这些方法时,可以明确指出字符集编码,也可以采用系统默认的方案,通常是 UTF-8
3、使用原始的 8 位值与 Unicode 字符串
使用原始的 8 位值与 Unicode 字符串时需要注意的两个问题:
-
该问题等价于:使用
bytes
和str
时需要注意的两个问题
3.1 问题一:bytes 和 str 的实例互不兼容
使用 + 操作符:
1
2
3
4
5
6
7
8
9
10
|
# bytes+bytes print (b 'a' + b '1' ) # str+str print ( 'b' + '2' ) # 输出结果 b 'a1' b2 |
-
bytes + bytes
,str + str
都是允许的 -
但
bytes + str
会报错
#
1
2
3
4
5
6
7
|
bytes + str print ( 'c' + b '2' ) # 输出结果 print ( 'c' + b '2' ) TypeError: can only concatenate str ( not "bytes" ) to str |
同类型之间也可以用二元操作符来比较大小
1
2
3
|
assert b 'c' > b 'a' assert 'c' > 'a' |
但 bytes
和 str
之间用二元操作符也会报错
1
2
3
4
5
6
|
assert b 'c' > 'a' # 输出结果 assert b 'c' > 'a' TypeError: '>' not supported between instances of 'bytes' and 'str' |
判断 bytes
与 str
实例是否相等
两个类型的实例相比较总会为 False
,即使字符完全相同
1
2
3
4
5
6
|
# 判断 str、bytes print ( 'a' = = b 'a' ) # 输出结果 False |
格式化字符串中的 %s
两种类型的实例都可以出现在 %
操作符的右侧,用来替换左侧那个格式字符串(format string
)里面的 %s
但是!如果格式字符串是 bytes
类型,那么 不能 用 str
实例来替换其中的 %s
,因为 Python
不知道这个 str
应该按照什么字符集来编码
1
2
3
4
5
6
7
|
# % print (b 'red %s' % 'blue' ) # 输出结果 print (b 'red %s' % 'blue' ) TypeError: % b requires a bytes - like object , or an object that implements __bytes__, not 'str' |
但是!反过来却可以,如果格式字符串是 str 类型,则 可以 用bytes
实例来替换其中的 %s
,但结果可能不是预期结果
1
2
3
4
5
6
|
# % print ( 'red %s' % b 'blue' ) # 输出结果 red b 'blue' |
这样会让系统在 bytes
实例上面调用 __repr__
方法
调用结果替换格式字符串里的 %s,因此程序会直接输出 b'blue'
,而不是输出 blue
3.2问题二:操作文件句柄时需要使用 Unicode 字符串操作
不能使用原始的 bytes
向文件写入二进制数据会报错:
1
2
3
4
5
6
7
8
|
# 写入二进制数据 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
即可正常写入二进制数据
1
2
3
4
5
6
7
8
9
10
11
|
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 can't 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 即可正常读取二进制数据:
1
2
3
4
5
6
|
with open ( 'test.txt' , "rb" ) as f: print (b "\xf1\xf2" = = f.read()) # 输出结果 True |
另一种改法,设置 encoding 参数指定字符串编码:
1
2
3
4
5
6
|
with open ( 'test.txt' , "r" , encoding = "cp1252" ) as f: print (f.read()) # 输出结果 ñò |
这样也不会有异常了
需要注意:当前操作系统默认的字符集编码,Python 一行代码查看当前操作系统默认的编码标准
在 cmd 中执行:
12> python3 -c 'import locale; print(locale.getpreferredencoding())'
UTF-8
到此这篇关于Effective Python bytes 与 str 的区别的文章就介绍到这了,更多相关Python bytes 与 str 的区别内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!
原文链接:https://www.cnblogs.com/poloyy/p/15549664.html