欢迎加入python学习交流群 667279387

近期有同学在群里面问编解码的问题,为啥在python2中可以到了python3中为啥不行了。其实这设计到python2和python3编码的问题。这是一篇写比较不错的文档分享:Pragmatic Unicode ,这里在原文的基础上面进行了一下整理。

一、什么是编解码

1、什么是unicode

Unicode(统一码、万国码、单一码)是计算机科学领域里的一项业界标准,包括字符集、编码方案等。Unicode 是为了解决传统的字符编码方案的局限而产生的,它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。

2、编码方式

字符集:为每一个字符分配一个唯一的 ID(码位 / 码点 / Code Point),编码规则:将码位转换为字节序列的规则(编码/解码 可以理解为 加密/解密 的过程)。为了将unicode字符转成bytes,需要进行编码,常见的编码方案有:UTF-16, UTF-32, UCS-2, UCS-4, UTF-8

二、python中的编解码

1、python2

1、str: 是比特序列

2、unicode: code points序列

>>> my_string = "Hello World"
>>> type(my_string)
<type 'str'> >>> my_unicode = u"Hi \u2119\u01b4\u2602\u210c\xf8\u1f24"
>>> type(my_unicode)
<type 'unicode'>

(1).encode() 和 .decode()

unicode .encode() → bytes //encode函数就是将unicode转换成bytes

bytes .decode() → unicode //对应的解码过程就是将bytes转成unicode

>>> my_unicode = u"Hi \u2119\u01b4\u2602\u210c\xf8\u1f24"
>>> len(my_unicode)
9 >>> my_utf8 = my_unicode.encode('utf-8')
>>> len(my_utf8)
19
>>> my_utf8
'Hi \xe2\x84\x99\xc6\xb4\xe2\x98\x82\xe2\x84\x8c\xc3\xb8\xe1\xbc\xa4' >>> my_utf8.decode('utf-8')
u'Hi \u2119\u01b4\u2602\u210c\xf8\u1f24'

更多请参考官方教程:https://docs.python.org/2/library/stdtypes.html?highlight=decode#str.decode

(2)编解码错误和处理

许多编码方案并能将全部的unicode字符进行编码。

>>> my_unicode.encode('ascii')
Traceback (most recent call last):
UnicodeEncodeError: 'ascii' codec can't encode characters in
position 3-8: ordinal not in range(128)

同样反过来,也并不是每一个str都是合法的unicode编码。

>>> my_utf8.decode("ascii")
Traceback (most recent call last):
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in
position 3: ordinal not in range(128) >>> "\x78\x9a\xbc\xde\xf0".decode("utf-8")
Traceback (most recent call last):
return codecs.utf_8_decode(input, errors, True)
UnicodeDecodeError: 'utf8' codec can't decode byte 0x9a in
position 1: invalid start byte

这是官网给出来的一个在不能完全编码采用哪种方案进行处理的示例。

>>> unicode('\x80abc', errors='strict')
Traceback (most recent call last):
...
UnicodeDecodeError: 'ascii' codec can't decode byte 0x80 in position 0:
ordinal not in range(128)
>>> unicode('\x80abc', errors='replace')
u'\ufffdabc'
>>> unicode('\x80abc', errors='ignore')
u'abc'

(3)令人抓狂的隐式转换

下面就是python2中比较用起来爽,但是有时又让你很抓狂的东西—隐式转换。看下面这个例子:

>>> u"Hello " + "world"
u'Hello world' >>> u"Hello " + ("world".decode("ascii"))
u'Hello world' >>> sys.getdefaultencoding()
'ascii'

你可以将str和unicode进行拼接,语法解析器会自动给你做隐式转换。当然在很多时候是可以很好完成你的工作的,但是有时却不好使:

>>> u"Hello " + my_utf8
Traceback (most recent call last):
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in
position 3: ordinal not in range(128) >>> u"Hello " + (my_utf8.decode("ascii"))
Traceback (most recent call last):
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in
position 3: ordinal not in range(128)

2、python3

这里将python2和python3做了一个对比放在下面的表格里面了。

—— python2 python3
str a sequence of bytes a sequence of code points (unicode)
unicode a sequence of code points (unicode) ——
bytes —— a sequence of bytes

也就是说在python中,字符串为unicode格式的码位。下面看看在python3中的示例

>>> my_string = "Hi \u2119\u01b4\u2602\u210c\xf8\u1f24"
>>> type(my_string)
<class 'str'> >>> my_bytes = b"Hello World"
>>> type(my_bytes)
<class 'bytes'>

(1)encode和decode

在python3中,字符串str是unicode的,你可以利用encode函数将其转成其他的编码格式。

>>> nonlat = '字' //unicode格式
>>> nonlat
'字'
>>> print(nonlat)

>>> bytes(nonlat)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: string argument without an encoding >>> bytes(nonlat, 'utf-8')//和下面直接调用encode方法的区别可以参考下面给出的Stack Overflow的链接
b'\xe5\xad\x97' >>> nonlat.encode() //encode函数默认使用utf-8编码
b'\xe5\xad\x97' >>> nonlat.encode('utf-16')
b'\xff\xfeW[' >>> b'\xff\xfeW['.decode('utf-8')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xff in position 0: invalid start byte >>> b'\xff\xfeW['.decode('utf-16')
'字'

区别:https://stackoverflow.com/questions/14472650/python-3-encode-decode-vs-bytes-str

更多请参考官方文档:https://docs.python.org/3/library/stdtypes.html?highlight=decode#bytes.decode

(2)无隐式转换

在python3中没有了python2中的隐式转换。你必须两种格式分开来处理。

>>> "Hello " + b"world"
Traceback (most recent call last):
TypeError: Can't convert 'bytes' object to str implicitly >>> "Hello" == b"Hello"
False >>> d = {"Hello": "world"}
>>> d[b"Hello"]
Traceback (most recent call last):
KeyError: b'Hello'

例如读取文件的时候,你就必须要注意格式的问题:

>>> open("hello.txt", "r").read()
'Hello, world!\n' >>> open("hello.txt", "rb").read()
b'Hello, world!\n' >>> open("hi_utf8.txt", "r").read()
'Hi \xe2\u201e\u2122\xc6\xb4\xe2\u02dc\u201a\xe2\u201e\u0152\xc3\xb8\xe1\xbc\xa4' >>> open("hi_utf8.txt", "r",
... encoding=locale.getpreferredencoding()).read()
'Hi \xe2\u201e\u2122\xc6\xb4\xe2\u02dc\u201a\xe2\u201e\u0152\xc3\xb8\xe1\xbc\xa4' >>> open("hi_utf8.txt", "r", encoding="utf-8").read()
'Hi \u2119\u01b4\u2602\u210c\xf8\u1f24' >>> open("hi_utf8.txt", "rb").read()
b'Hi \xe2\x84\x99\xc6\xb4\xe2\x98\x82\xe2\x84\x8c\xc3\xb8\xe1\xbc\xa4

(3)编程注意点

1、Unicode sandwich

Bytes on the outside, unicode on the inside Encode/decode at the edges



2、Know what you have

Bytes or Unicode? If bytes, what encoding?

>>> print type(my_unicode)
<type 'unicode'> >>> print repr(my_unicode)
u'Hi \u2119\u01b4\u2602\u210c\xf8\u1f24'

参考资料:

1、https://en.wikipedia.org/wiki/Unicode

2、https://docs.python.org/2/howto/unicode.html

3、https://stackoverflow.com/questions/14472650/python-3-encode-decode-vs-bytes-str

4、https://docs.python.org/3/library/stdtypes.html?highlight=decode#bytes.decode

欢迎加入python学习交流群 667279387

python2和python3编码问题的更多相关文章

  1. 字符编码、python2和python3编码的区别

    目录 字符编码 文本编辑器存储信息的过程 python解释器解释python代码的流程 python解释器与文本编辑器的异同 不同编码格式存入与读取数据的过程 乱码的分析 python2和python ...

  2. python2和python3编码

    python2编码 unicode:unicode 你好 u'\u4f60\u597d' | | | | encode('utf8')| |decode('utf8') encode('gbk')| ...

  3. Python2 和 Python3 编码问题

    基本存储单元 位(bit, b):二进制数中的一个数位,可以是0或者1,是计算机中数据的最小单位. 字节(Byte,B):计算机中数据的基本单位,每8位组成一个字节. 1B = 8b 各种信息在计算机 ...

  4. python2与python3编码

    #coding:utf8#一#1.在python2中,默认以ASCII编码chcp 936import sysprint sys.getdefaultencoding()# ascii#str:byt ...

  5. Python2和Python3编码的区别

    Python2 python2中有两种储存变量的形式,第一种:Unicode:第二种:按照coding头来的. 假设python2用utf8存储x='中文',当你print(x)的时候,终端接收gbk ...

  6. python2与python3编码问题

    python2: UnicodeDecodeError: 'ascii' codec can't decode byte 0xc4 in position 33: 解决办法: 在报错的页面添加代码:  ...

  7. python2与python3编码(练习)

    #_author:来童星#date:2019/12/9import jsons='star'a=s.encode('utf8')print(s,type(s))# star <class 'st ...

  8. pickle 在python2 to python3 编码出现错误

    pickle.load(file) UnicodeDecodeError: 'ascii' codec can't decode byte 0xf5 in position 2: ordinal no ...

  9. Python全栈之路----Python2与Python3

    金角大王Alex  python 之路,致那些年,我们依然没搞明白的编码 python2与python3的区别 py2 str = bytes 为什么有bytes? 是因为要表示图片.视频等二进制格式 ...

随机推荐

  1. vue , debounce 使用

    有时候不想直接在methods中的方法前面加debounce, getFullName: debounce(function() { console.log('my fullname is chent ...

  2. python模块——socket

    实例一. server: #socket套接字(IP + 端口号)(qq,wechat 发送接收消息依靠socket模块),cs架构import socketserver = socket.socke ...

  3. linux中jdk的安装

    //先检查jdk有没有安装 java -version   cp jdk-7u79-linux-x64.tar.gz /usr/local/ cd /usr/local/ tar -zxvf jdk- ...

  4. Java基础:数值类型转换、强制类型转换

    数值类型之间的转换 数值类型之间的转换,在小数值往大数值转换时,不会发生精度的损失.在小数值往大数值转换时有可能发生精度的损失. 比如byte最大值也只有127,如果一个大于127的int类型数据往b ...

  5. OFFICE 2010 每次打开提示安装的问题

    OFFICE2010 安装后每次打开 文件总是提示配置 解决办法: 前提是office已经激活 注册表找到 HKEY_CURRENT_USER\Software\Microsoft\Office\14 ...

  6. thinkphp 5.1 去掉 .html 后缀

    thinkphp 5.1 去掉 .html 后缀  

  7. 一文带你深入了解 redis 复制技术及主从架构

    主从架构可以说是互联网必备的架构了,第一是为了保证服务的高可用,第二是为了实现读写分离,你可能熟悉我们常用的 MySQL 数据库的主从架构,对于我们 redis 来说也不意外,redis 数据库也有各 ...

  8. 新闻实时分析系统-Kafka分布式集群部署

    Kafka是由LinkedIn开发的一个分布式的消息系统,使用Scala编写,它以可水平扩展和高吞吐率而被广泛使用.目前越来越多的开源分布式处理系统如Cloudera.Apache Storm.Spa ...

  9. 【Luogu P4779】dijkstra算法的堆优化

    Luogu P4779 利用堆/优先队列快速取得权值最小的点. 在稠密图中的表现比SPFA要优秀. #include<iostream> #include<cstdio> #i ...

  10. 推荐几个不错的console调试技巧

    在我们的日常前端开发中,使用最频繁的莫过于使用console.log在浏览器的控制台中打印出我们需要调试的信息,但是大部分人可能跟之前的我一样,没有意识到其实console除了log方法以外,还有很多 ...