Effective Python(3)- 了解 bytes 与 str 的区别

简介: Effective Python(3)- 了解 bytes 与 str 的区别

Python 有两种类型可以表示字符序列


  • bytes:实例包含的是原始数据,即 8 位的无符号值(通常按照 ASCII 编码标准来显示)
  • str:实例包含的是 Unicode 码点(code point,也叫作代码点),这些码点与人类语言之中的文本字符相对应


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


Unicode 数据和二进制数据转换


  • 把  Unicode 数据转换成二进制数据,必须调用 str 的 encode 方法(编码)
  • 把二进制数据转换成 Unicode 数据,必须调用 bytes 的 decode 方法(解码)
  • 调用这些方法时,可以明确指出字符集编码,也可以采用系统默认的方案,通常是 UTF-8

 

使用原始的 8 位值与 Unicode 字符串时需要注意的两个问题


该问题等价于:使用 bytes 和 str 时需要注意的两个问题

 

问题一:bytes 和 str 的实例互不兼容


使用 + 操作符

# bytes+bytes
print(b'a' + b'1')
# str+str
print('b' + '2')
# 输出结果
b'a1'
b2


  • bytes + bytes,str + str 都是允许的
  • 但 bytes + str 会报错


# bytes+str
print('c' + b'2')
# 输出结果
print('c' + b'2')
TypeError: can only concatenate str (not "bytes") to str


同类型之间也可以用二元操作符来比较大小

assert b'c' > b'a'


assert'c' > 'a'

但 bytes 和 str 之间用二元操作符也会报错

assert b'c' > 'a'



# 输出结果

   assert b'c' > 'a'

TypeError: '>'not supported between instances of 'bytes'and'str'

 

判断 bytes 与 str 实例是否相等

两个类型的实例相比较总会为 False,即使字符完全相同

# 判断 str、bytes
print('a' == b'a')
# 输出结果
False


格式化字符串中的 %s

两种类型的实例都可以出现在 % 操作符的右侧,用来替换左侧那个格式字符串(format string)里面的 %s

但是!如果格式字符串是 bytes 类型,那么不能用 str 实例来替换其中的 %s,因为 Python 不知道这个 str 应该按照什么字符集来编码

# %
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,但结果可能不是预期结果

# %

print('red %s' % b'blue')



# 输出结果

red b'blue'

  • 这样会让系统在 bytes 实例上面调用 __repr__ 方法
  • 调用结果替换格式字符串里的 %s,因此程序会直接输出 b'blue',而不是输出 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 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 即可正常读取二进制数据

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())
# 输出结果
ñò


这样也不会有异常了

 

重点


需要注意当前操作系统默认的字符集编码

https://www.cnblogs.com/poloyy/p/15536156.html

相关文章
|
2月前
|
存储 开发者 Python
Python 中的数据结构与其他编程语言数据结构的区别
不同编程语言都有其设计理念和应用场景,开发者需要根据具体需求和语言特点来选择合适的数据结构
|
3月前
|
存储 大数据 数据处理
Python 中的列表推导式与生成器:特性、用途与区别
Python 中的列表推导式与生成器:特性、用途与区别
36 2
|
3月前
|
存储 C语言 Python
解密 Python 的变量和对象,它们之间有什么区别和联系呢?
解密 Python 的变量和对象,它们之间有什么区别和联系呢?
32 2
|
4月前
|
存储 Python
Python中类方法、实例方法与静态方法的区别
这三种方法的正确使用可以使代码更加清晰、组织良好并且易于理解,从而有效地支持软件开发的面向对象编程范式。
65 1
|
3月前
|
机器学习/深度学习 缓存 Linux
python环境学习:pip介绍,pip 和 conda的区别和联系。哪个更好使用?pip创建虚拟环境并解释venv模块,pip的常用命令,conda的常用命令。
本文介绍了Python的包管理工具pip和环境管理器conda的区别与联系。pip主要用于安装和管理Python包,而conda不仅管理Python包,还能管理其他语言的包,并提供强大的环境管理功能。文章还讨论了pip创建虚拟环境的方法,以及pip和conda的常用命令。作者推荐使用conda安装科学计算和数据分析包,而pip则用于安装无法通过conda获取的包。
166 0
|
4月前
|
Python
全网最适合入门的面向对象编程教程:Python函数方法与接口-函数与方法的区别和lamda匿名函数
【9月更文挑战第15天】在 Python 中,函数与方法有所区别:函数是独立的代码块,可通过函数名直接调用,不依赖特定类或对象;方法则是与类或对象关联的函数,通常在类内部定义并通过对象调用。Lambda 函数是一种简洁的匿名函数定义方式,常用于简单的操作或作为其他函数的参数。根据需求,可选择使用函数、方法或 lambda 函数来实现代码逻辑。
|
4月前
|
机器学习/深度学习 人工智能 安全
python和Java的区别以及特性
Python:适合快速开发、易于维护、学习成本低、灵活高效。如果你需要快速上手,写脚本、数据处理、做点机器学习,Python就是你的首选。 Java:适合大型项目、企业级应用,性能要求较高的场景。它类型安全、跨平台能力强,而且有丰富的生态,适合更复杂和规模化的开发。
81 3
|
4月前
|
存储 编译器 Linux
Cython 和 Python 的区别
Cython 和 Python 的区别
54 0
|
4月前
|
Python
Python中类属性与实例属性的区别
了解这些区别对于编写高效、易维护的Python代码至关重要。正确地使用类属性和实例属性不仅能帮助我们更好地组织代码,还能提高代码运行的效率。
42 0
|
5月前
|
存储 测试技术 Python
Python 数组和列表有什么区别?
【8月更文挑战第29天】
854 4