关于 Python2 和 Python3 中的 Unicode 问题。
写在之前
字符编码问题几乎是会跟随我们整个编程生涯的一大魔障,一不小心各种玄学的问题就会接踵而至,防不胜防,尤其是对初学者来说,碰到编码问题简直是就是加快了踏上从入门到放弃的传送带。
鉴于我公众号的读者初学者占了一大部分,所以很多时候我会收到各种询问字符编码的问题,这里面有用 Python2 的,也有用 Python3 的,鉴于在编码问题上这两种版本的 Python 有着很大的不同,所以在这篇文章中我都会讲到。
在往下看之前,希望你先了解一下编码,字符编码以及其发展史这些概念,我在很久之前的文章里写过(零基础学习 Python 之字符编码),不了解的可以看一下。
字符集问题
很多时候在使用 Python 编程的时候,如果不使用 Unicode,处理中文的时候会出现一些让人头大的事情,当然这个是针对 Python2 版本来说的,因为 Python3 默认使用的是 Unicode。具体如下所示:
>>> name = '李四'
>>> name
'\xe6\x9d\x8e\xe5\x9b\x9b'
>>> print(name)
李四
>>> len(name)
6
>>> name[:1]
'\xe6'
>>> print(name[:1])
?
通过上面的例子可以看到,我们在代码中使用中文以后,求字符串的长度和对其进行切片操作都没有按照我们预想的方式输出结果,当然有懂得读者知道这个问题用 Unicode 就可以轻松解决,但真的是轻松解决么?如果你对字符集编码只是半瓶子醋,新出现的问题又会让你头大如斗。具体如下所示:
>>> name = u'李四'
>>> name
u'\u674e\u56db'
>>> name[:1]
u'\u674e'
>>> print(name[:1])
李
>>> with open('./Desktop/test', 'a') as f:
... f.write(name)
...
Traceback (most recent call last):File "<stdin>", line 2, in <module>
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
上述的代码出现了错误,报错的原因很简单,因为我们定义了一个 Unicode 字符串 u’李四’,然后我们想把它保存到文本文件里,但是我们没有指定文件的编码,所以默认的是 ASCII 编码,显然用 Unicode 表示的汉字是无法用 ASCII 码存储的,所以就抛出了 UnicodeEncodeError 异常。
Python2 & Python3 的 Unicode
前面铺垫的够多,现在我们算是正式来看 Python 中的字符串与字符编码之间的调用。
首先来说 Python3,Python3 里有两种表示字符序列的类型,分别是 bytes 和 str,bytes 的实例包含 8 位值,str 的则包含 Unicode 字符。Python2 中也有两种表示字符序列的类型,分别是 str 和 Unicode,它与 Python3 的不同是,str 的实例包含原始的 8 位值,而 Unicode 的实例包含 Unicode 字符。这是什么意思呢?也就是说 Python3 中字符串默认为 Unicode,但是如果在 Python2 中需要使用 Unicode,必须要在字符串的前面加一个 「u」前缀,形式参考上面例子中的写法。
当然了,在 Python2 中也可以默认使用 Unicode 的字符串,执行下面的操作即可:
from __future__ import unicode_literals
Python 字符串有 encode 和 decode 方法,用这两个可以对字符串进行编码或解码,我们来看一个在 Python2 下运行的例子:
>>> name = '李四'
>>> name
'\xe6\x9d\x8e\xe5\x9b\x9b'
>>> my_name = name.decode('utf8')
>>> my_name
u'\u674e\u56db'
>>> print(my_name)
李四
>>> my_name.encode('utf-8')
'\xe6\x9d\x8e\xe5\x9b\x9b'
既然我们知道了 encode 用于编码,decode 用于解码,那么对于之前我们抛出异常的那个例子我们可以手动解决,具体如下所示:
>>> with open('./Desktop/data.txt', 'a') as f:
... f.write(name.encode('utf-8'))
...
>>> with open('./Desktop/data.txt', 'r') as f:
... data = f.read()
...
>>> data.decode('utf-8')
u'\u674e\u56db'
上述代码是字符串较短的情况,如果需要写入的字符串很多,每次都要手动进行编码将会变的非常低效,Python2 中有个「codecs」模块可以解决这个问题:
>>> import codecs
>>> name
u'\u674e\u56db'
>>> with codecs.open('./Desktop/data.txt', 'w', encoding='utf-8') as f:
... f.write(name)
...
>>> with codecs.open('./Desktop/data.txt', 'r', encoding='utf-8') as f:
... data = f.read()
...
>>> data
u'\u674e\u56db'
而在 Python3 中内置的 open 就已经支持指定编码风格:
>>> name = '李四'
>>> name
'李四'
>>> with open('./Desktop/data.txt', 'w', encoding='utf-8') as f:
... f.write(name)
...
2
把 Unicode 字符表示为二进制的数据有很多种办法,最常见的就是 utf-8,但是这里需要我们明白的是,Unicode 是表现形式,utf-8 是存储形式,utf-8 虽然是使用最广泛的编码,但也仅仅是 Unicode 的一种存储形式罢了。
当然字符编码的问题还有很多,我也不可能面面俱到,最后我还是希望你可以在一开始的时候就彻底的搞定字符编码的东西,拿出一些时间来好好研究一下,不然这个东西会成为你编码路上挥之不去的“噩梦”。
更多内容,欢迎关注公众号「Python空间」,期待和你的交流。
关于 Python2 和 Python3 中的 Unicode 问题。相关推荐
- python2 md5库_python版本坑:md5例子(python2与python3中md5区别)
起步 对于一些字符,python2和python3的md5加密出来是不一样的. # python2.7 pwd = "xxx" + chr(163) + "fj" ...
- oracle urlencode 中文,Python2和Python3中urllib库中urlencode的使用注意事项
前言 在Python中,我们通常使用urllib中的urlencode方法将字典编码,用于提交数据给url等操作,但是在Python2和Python3中urllib模块中所提供的urlencode的包 ...
- python3生成一个定长列表_range方法在Python2和Python3中的不同
range 列表 range()方法是Python中常用的方法, 但是在Python2和Python3中使用方法不同,下面看下它们的不同使用方法. range方法详解 range(start, sto ...
- python2与python3性能对比_对Python2与Python3中__bool__方法的差异详解
对Python2与Python3中__bool__方法的差异详解 发布时间:2020-08-28 00:08:58 来源:脚本之家 阅读:74 作者:grey_csdn 学习Python面向对象编程的 ...
- range方法在Python2和Python3中的不同
range()方法是Python中常用的方法, 但是在Python2和Python3中使用方法不同,下面看下它们的不同使用方法. range方法详解 range(start, stop[, step] ...
- Python2和python3中类型判断
Python2类型判断 >>> type(33) == types.IntType True >>> type("33") == types.S ...
- python2和python3中encoding的差别
1.写在前面的话 对于一些python库,比如:requests,会用到编码和解码(requests.utils.get_encodings_from_content()),还记得写在python文件 ...
- python2和python3中的range区别
python2中的range返回的是一个列表 python3中的range返回的是一个迭代值 for i in range(1,10)在python2和python3中都可以使用,但是要生成1-10的 ...
- Python2和Python3中除法运算符的区别有哪些?你都知道吗?
在Python2中,除法的取值结果取整数 >>>7/3 2 即一个整数(无小数部分的数)被另外一个整数除,计算结果的小数部分被截除了,只留下了整数部分. 在Python3中,除法/的 ...
最新文章
- Ubuntu 查看磁盘空间大小命令转
- contains与compareDocumentPosition方法详解
- 重庆python培训-重庆python培训机构排.行榜
- Kylin的cube模型
- 【机器学习】异常检测算法之(HBOS)-Histogram-based Outlier Score
- node.js学习笔记14—微型社交网站
- 《电子基础与维修工具核心教程》——2.4 电阻的串并联
- 和男朋友一块儿吃VS单独一人在家吃饭
- vim中的jk为什么是上下_JK的完整形式是什么?
- JavaScript 字符串属性和方法
- 使用OWA无法撰写邮件内容的解决法
- Django入门文档
- deepin有线网卡无法连接网络
- S3C2410,ARM920T,试题总结
- STM32L476入坑-3-新建工程并点亮LED灯
- 如何挑选合适的卫星影像
- 管螺纹如何标注_你所不知道的机械螺纹全面常识(分享篇),赶紧收藏下吧
- 软件定义边界(SDP)简介
- 重装服务器系统只装C盘,如何只重装C盘的系统?
- eclipse的jdt简介