Python 3 最重要的新特性之一是对字符串和二进制数据流做了明确的区分文本总是 Unicode, 由 str 类型表示, 二进制数据则由 bytes 类型表示 Python 3 不会以任意隐式的方式混用 str 和 bytes, 你不能拼接字符串和字节流, 也无法在字节流里搜索字符串(反之亦然), 也不能将字符串传入参数为字节流的函数(反之亦然)
编码发展的历史
在谈 bytes 和 str 之前, 需要先说说关于编码是如何发展的
在计算机历史的早期, 美国为代表的英语系国家主导了整个计算机行业, 26 个英文字母组成了多样的英语单词语句文章因此, 最早的字符编码规范是 ASCII 码, 一种 8 位即 1 个字节的编码规范, 它可以涵盖整个英语系的编码需要
编码是什么? 编码就是把一个字符用一个二进制来表示我们都知道, 所有的东西, 不管是英文中文还是符号等等, 最终存储在磁盘上都是 01010101 这类东西在计算机内部, 读取和存储数据归根结底, 处理的都是 0 和 1 组成的比特流问题来了, 人类看不懂这些比特流, 如何让这些 010101 对人类变得可读呢? 于是出现了字符编码, 它是个翻译机, 在计算机内部某个地方, 透明的帮我们将比特流翻译成人类可以直接理解的文字对于一般用户, 不需要知道这个过程是什么原理, 是怎么执行的但是对于程序员却是个必须搞清楚的问题
以 ASCII 编码为例, 它规定 1 个字节 8 个比特位代表 1 个字符的编码, 也就是 00000000 这么宽, 一个一个字节的解读例如: 01000001 表示大写字母 A, 有时我们会偷懒 " 的用 65 这个十进制来表示 A 在 ASCII 中的编码 8 个比特位, 可以没有重复的最多表示 2 的 8 次方 (255) 个字符
后来, 计算机得到普及, 中文日文韩文等等国家的文字需要在计算机内表示, ASCII 的 255 位远远不够, 于是标准组织制定出了叫做 UNICODE 的万国码, 它规定任何一个字符 (不管哪国的) 至少以 2 个字节表示, 可以更多其中, 英文字母就是用 2 个字节, 而汉字是 3 个字节这个编码虽然很好, 满足了所有人的要求, 但是它不兼容 ASCII, 同时还占用较多的空间和内存因为, 在计算机世界更多的字符是英文字母, 明明可以 1 个字节就能够表示, 非要用 2 个
于是 UTF-8 编码应运而生, 它规定英文字母系列用 1 个字节表示, 汉字用 3 个字节表示等等因此, 它兼容 ASCII, 可以解码早期的文档 UTF-8 很快就得到了广泛的应用
在编码的发展历程中, 我国还创造了自己的编码方式, 例如 GBK,GB2312,BIG5 他们只局限于在国内使用, 不被国外认可在 GBK 编码中, 中文汉字占 2 个字节
byte 和 str 之间的异同:
回到 bytes 和 str 的身上 bytes 是一种比特流, 它的存在形式是 01010001110 这种我们无论是在写代码, 还是阅读文章的过程中, 肯定不会有人直接阅读这种比特流, 它必须有一个编码方式, 使得它变成有意义的比特流, 而不是一堆晦涩难懂的 01 组合因为编码方式的不同, 对这个比特流的解读也会不同, 对实际使用造成了很大的困扰
s = 中文
- print(type(s)) #<class str>
- b = bytes(s,encoding=utf-8,errors=strict)
- print(b) #b\xe4\xb8\xad\xe6\x96\x87
- print(type(b)) #<class bytes>
- s2 = str(b,encoding=utf-8,errors=strict)
- print(s2) #中文
- print(type(s2)) #<class str>
从例子可以看出, s 是个字符串类型 Python 有个内置函数 bytes()可以将字符串 str 类型转换成 bytes 类型, b 实际上是一串 01 的组合, 但为了在 ide 环境中让我们相对直观的观察, 它被表现成了
b\xe4\xb8\xad\xe6\x96\x87
这种形式, 开头的 b 表示这是一个 bytes 类型 \ xe4 是十六进制的表示方式, 它占用 1 个字节的长度, 因此中文被编码成 utf-8 后, 我们可以数得出一共用了 6 个字节, 每个汉字占用 3 个, 这印证了上面的论述在使用内置函数 bytes()的时候, 必须明确 encoding 的参数, 不可省略, str()也类似
我们都知道, 字符串类 str 里有一个 encode()方法, 它是从字符串向比特流的编码过程而 bytes 类型恰好有个 decode()方法, 它是从比特流向字符串解码的过程除此之外, 我们查看 Python 源码会发现 bytes 和 str 拥有几乎一模一样的方法列表, 最大的区别就是 encode 和 decode
从实质上来说, 字符串在磁盘上的保存形式也是 01 的组合, 也需要编码解码
总结:
1 在将字符串写入磁盘或者从磁盘读取字符串的时候, Python 会自动的完成编码和解码的工作
2 在使用 bytes()的时候, 实际就是告诉 Python, 不需要 Python 帮你进行编码, 你会手动对输入的字符串进行编码, 并且可以指定编码格式
3 在 Python 3 中对 byte 和 str 进行了严格的区分, 不能在需要 byte 类型参数的时候, 使用 str 类型参数
两种方式:
# 将 str 转换为 byte
unicode_string = 中文
- print(type(unicode_string)) #<class str>
- #第一种
- bytearray = unicode_string.encode() #def encode(self, encoding=utf-8, errors=strict), 默认就是 utf-8 的编码方式
- print(bytearray) #b\xe4\xb8\xad\xe6\x96\x87
- print(type(bytearray)) #<class bytes>
- #第二种
- bytearray2 = bytes(unicode_string,encoding=utf-8,errors=strict) #def __init__(self, value=b, encoding=None, errors=strict)
- print(bytearray2) #b\xe4\xb8\xad\xe6\x96\x87
- print(type(bytearray2)) #<class bytes>
- #将 byte 转换为 str
- bytearray = b\xe4\xb8\xad\xe6\x96\x87
- print(type(bytearray)) #<class bytes>
- #第一种
- unicode_string = bytearray.decode()
- print(unicode_string) #中文
- print(type(unicode_string)) #<class str>
- #第二种
- unicode_string2 = str(bytearray,encoding=utf-8,errors=strict)
- print(unicode_string2) #中文
- print(type(unicode_string2)) #<class str>
参考:
Chown-Jane-Y https://home.cnblogs.com/u/chownjy/
Python 3 最重要的新特性之一是对字符串和二进制数据流做了明确的区分文本总是 Unicode, 由 str 类型表示, 二进制数据则由 bytes 类型表示 Python 3 不会以任意隐式的方式混用 str 和 bytes, 你不能拼接字符串和字节流, 也无法在字节流里搜索字符串(反之亦然), 也不能将字符串传入参数为字节流的函数(反之亦然)
来源: http://www.bubuko.com/infodetail-2545299.html