Python的编码问题笔记(搞清原理, 一劳永逸)
近日常常python的编码问题纠缠的生活不能自理. 昨天终于静下心来看了看文档, 把Python3中的编码搞清, 用这篇文章分享记录一下**(包括utf-8的原理)**.
提示:
下文中都是以python3为栗子🌰.
因为python3慢慢变成主流, 而且用python2的话我一般会写成兼容的模式:>>> from __future__ import print_function, unicode_literals
编码在python2和3中的区别(可跳过, 最后回过头来看):
摘自 Effective Python 那本书:
**In Python3: **
- bytes: sequences of 8-bit values.
- str: sequences of Unicode characters.
bytes and str instances can’t be used with operators(like > or +)In Python 2:
- str: contains sequences of 8-bit values.
- unicode: contains sequences of Unicode characters.
str and unicode can be used together with operators if the str only contains 7-bit ASCII characters.
但说实话在今天前, 我对上边那段话的理解还是停留在python3 有两种类型(str和bytes)的地步😓.
1. Python3 str类型(unicode)
python3的str字符串, 默认就代表unicode字符组成的序列.
In [1]: s = '哈哈哈'
In [2]: type(s)
Out[2]: str
那问题来了, 到底什么是unicode呢?
大家都知道ASCII编码, 它用7位bits代表128个字符.
但一个字节不够用的时候, 很多聪明的人就发明了很多的扩展的字符集.
可是这时候碰到了一个问题, 就是一台电脑在美利坚可能用的好好的, 但如果收到日本的邮件, 那就GG了, 因为两台电脑的编码方式不同.
所有后来更聪明的人就想到了unicode:
它对世界上所有的字符进行收集, 每个字符指向一个code point(简单理解为一个唯一的数字), 这样全世界交流也不会乱码了, 棒棒哒.
所以unicode的一个中文名也叫万国码
.
2. Python3 bytes类型(字节)
bytes和str一样都是内置的类型:
In [7]: s = b'haha'
In [8]: type(s)
Out[8]: bytes
个人理解, 它代表的就是以字节(byte)为单位存储的二进制, i.e. 一坨的bytes
3. Encoding/decoding:
搞清楚python中的str和bytes类型, 这个问题就迎刃而解了.
Encoding:
str → bytes
因为str只是一堆unicode字符(数字).
所以简单的说, encoding就是把一堆数字, 按特定的编码算法X(例如utf-8), 用字节的方式存储在计算机上.Decoding:
bytes → str
举个栗子🌰:
In [9]: s = '哈哈'
In [10]: s.encode('utf-8')
Out[10]: b'\xe5\x93\x88\xe5\x93\x88'
In [11]: s.encode().decode('utf-8')
Out[11]: '哈哈'
4. UTF-8编码(encoding)
简单的说下unicode是如何通过utf-8编码转化为bytes, 以帮助更好的理解什么是编码(encoding).
utf-8其实属于 动态长度编码(variable length encoding).
举个动态长度编码简单的栗子, 假如说有这么一个二进制序列:
10010001, 10000001, 10110010, 10110010
我们就可以利用每个byte的最后一位(标志位, 1代表继续, 0代表结束), 来判断读几个bytes.
utf-8也是类似的思想, 但不同于上边, 它是用每个字节开头的几位, 当作标志位, 如下表所示:
(生动活泼形象的编码例子见下图↓)
总结
为此我专门画了一张图, 总结了一下: