详解Python中的编码问题(encoding与decode、str与bytes)


Posted in Python onSeptember 30, 2020

1 引言

在文件读写及字符操作时,我们经常会出现下面这几种错误:

  • TypeError: write() argument must be str, not bytes

  • AttributeError: 'URLError' object has no attribute 'code'

  • UnicodeEncodeError: 'gbk' codec can't encode character '\xa0' inposition 5747: illegal multibyte sequence

这些错误一看就是编码问题, 本篇博文总结一下Python3文件读写及字符操作中的编码。

2 编码发展史

(1)ASCII编码

众所周知,计算机只能处理0和1,任何符号都转换为0和1的序列才能处理。计算机中8个位(bit)作为一个字节,所以1个字节能产生2的8次方个0和1的不同组合,也就是说1个字节做多能表示256种字符。ASCII编码就是用1个字节来存储字符,计算机最初是美国人发明的,他们的符号不多,所以还将8个0和1序列中的第一位固定为0,ASCII只能表示127个字符。

(2)GB2312编码

美国佬的符号不多,所以ASCII编码够用,但是其他国家就不行了,每个国家符号数量都不一样,就各自指定了自己的编码。例如我们中国就制定了GB2312编码。GB2312编码用2个字节表示一个字符。

(3)Unicode编码

每个国家都用自己的编码,编码一朵就容易乱套,也没法交流,所以需要一种编码把各个国家的编码都囊括进去,这就是Unicode编码的由来。所以,Unicode也被称为万国码。Unicode编码也用2个字节存储一个字符。

(4)utf-8编码

Unicode编码解决了编码不能通用的问题,但是却容易浪费内存,尤其是在存储英文的时候,例如一个字符“A”,ASCII编码只需要1个字节就够,但是Unicode编码必须要用2个字节。为了解决这一问题,就有了utf-8编码。 utf-8编码把存储英文依旧用一个字节,汉字就3个字节。特别是生僻的编程4-6字节,如果传输大量英文,utf-8作用就很明显了。
utf-8编码进行存储时有极大地优势,但是当读取到计算机内存时却不大合适,因为utf-8编码是变长的,不方便寻址和索引,所以在计算机内存中,还是转化为Unicode编码合适些。这就可以解释为什么每次读取文本时,要将编码转化为Unicode编码,而将内存中的字符写入文件存储时,要将编码转化为utf-8了。

3 str与bytes

在Python3中,文本总是为Unicode编码,在类型上为str类,也就是说Python编译器只会把Unicode编码下的二进制流显示为我们可识别的符号。二进制流在Python中也有一个专门的类用于表示这种二进制序列,那就是bytes(在Python中这个二进制序列显示为16进制,但本质还是二进制)。一个str在不同的编码下就可以转化为不同的bytes(二进制流),反之,要将bytes转化为可识别的str就必须用对应的编码,否则就会报错。

用人类语言类比一下:我们要表达“吃饭”这件事物(str),翻译为各个国家的文字后有各不相同的表示,中文表示为“吃饭”,英文表示为“eat”,这就是“吃饭”这个str在不同编码写的表示。但官方只认中文(Pythonstr只认Unicode编码),所以就必须把“eat”用英语(编码)的表示方式转化为中文的“吃饭”(Unicode编码),官方才会显示知道是吃饭这件事。

>>> s = '吃饭'
>>> type(s)
<class 'str'>
>>> s1 = s.encode(encoding='utf-8')
>>> type(s1)
<class 'bytes'>
>>> s1
b'\xe5\x90\x83\xe9\xa5\xad'
>>> s2 = s.encode(encoding='gb2312')
>>> type(s2)
<class 'bytes'> 
>>> s2
b'\xb3\xd4\xb7\xb9'
>>> s1.decode('utf-8')
'吃饭'
>>> s2.decode('gb2312')
'吃饭'

详解Python中的编码问题(encoding与decode、str与bytes)

4 文件编码

在python 3 中字符是以Unicode的形式存储的,当然这里所说的存储是指存储在计算机内存当中,如果是存储在硬盘里,Python 3的字符是以bytes形式存储,也就是说如果要将字符写入硬盘,就必须对字符进行encode。对上面这段话再解释一下,如果要将str写入文件,如果以‘w'模式写入,则要求写入的内容必须是str类型;如果以‘wb'形式写入,则要求写入的内容必须是bytes类型。文章开头出现的几种错误,就是因为写入模式与写入内容的数据类型不匹配造成的。

s1 = '你好'
#如果是以‘w'的方式写入,写入前一定要进行encoding,否则会报错 
with open('F:\\1.txt','w',encoding='utf-8') as f1:
 f1.write(s1)
s2 = s1.encode("utf-8")#转换为bytes的形式
#这时候写入方式一定要是‘wb',且一定不能加encoding参数
with open('F:\\2.txt','wb') as f2:
 f2.write(s2)

有的人会问,我在系统里面用文本编辑器打开以bytes形式写入的2.txt文件,发现里面显示的是‘你好',而不是‘b'\xe4\xbd\xa0\xe5\xa5\xbd'',因为文本文档打开2.txt时,系统会用合适的编码将其显示为对应的符号,然后才给你看到。

5 网页编码

网页编码和文件编码方法差不多,如下urlopen下载下来的网页read()且用decoding(‘utf-8')解码,那就必须以‘w'的方式写入文件。如果只是read()而不用encoding(‘utf-8')进行编码,一定要以‘wb'方式写入:

以‘w'方式写入时:

response= url_open('http://blog.csdn.net/gs_zhaoyang/article/details/13768925 ' ,timeout=5 )#自定义的一个网页下载函数
#此处以UTF-8方式进行解码,解码后的数据以unicode的方式存储在html中
html = response.read().decode('UTF-8')
print(type(html))#输出结果:<class 'str'>
#这时写入方式一定要加encoding,以encoding
# 即UTF-8的方式对二进制数据进行编码才能写入
with open('F:\DownloadAppData\html.txt',"w" , encoding='UTF-8') as f:
 f.write(html)

以‘wb'方式写入:

response= url_open('http://blog.csdn.net/gs_zhaoyang/article/details/13768925 ' ,timeout=5 )
html = response.read()#此处不需要进行解码,下载下来
print(type(html))#输出结果:<class 'bytes'>
with open('F:\DownloadAppData\html.txt',"wb" ) as f:
 f.write(html)

如果要在Python3中,对urlopen下载下来的网页进行字符操作(例如正则匹配、lxml提取),就必须decode成Unicode。

作者:奥辰

微信号:chb1137796095

Github:https://github.com/ChenHuabin321

欢迎加V交流,共同学习,共同进步!

以上就是详解Python中的编码问题(encoding与decode、str与bytes)的详细内容,更多关于python 编码的资料请关注三水点靠木其它相关文章!

Python 相关文章推荐
Python使用代理抓取网站图片(多线程)
Mar 14 Python
python进阶教程之文本文件的读取和写入
Aug 29 Python
python使用socket进行简单网络连接的方法
Apr 29 Python
Python标准模块--ContextManager上下文管理器的具体用法
Nov 27 Python
python绘制圆柱体的方法
Jul 02 Python
PyQt5 窗口切换与自定义对话框的实例
Jun 20 Python
python中用logging实现日志滚动和过期日志删除功能
Aug 20 Python
Django+uni-app实现数据通信中的请求跨域的示例代码
Oct 12 Python
Python 实现OpenCV格式和PIL.Image格式互转
Jan 09 Python
python_matplotlib改变横坐标和纵坐标上的刻度(ticks)方式
May 16 Python
django表单中的按钮获取数据的实例分析
Jul 31 Python
详解查看Python解释器路径的两种方式
Oct 15 Python
python 生成器需注意的小问题
Sep 29 #Python
python 两种方法删除空文件夹
Sep 29 #Python
如何使用python写截屏小工具
Sep 29 #Python
python如何调用百度识图api
Sep 29 #Python
Python 串口通信的实现
Sep 29 #Python
使用py-spy解决scrapy卡死的问题方法
Sep 29 #Python
详解python对象之间的交互
Sep 29 #Python
You might like
Apache服务器无法使用的解决方法
2013/05/08 PHP
php采用curl模仿登录人人网发布动态的方法
2014/11/07 PHP
TP3.2.3框架使用CKeditor编辑器在页面中上传图片的方法分析
2019/12/31 PHP
Js+Dhtml:WEB程序员简易开发工具包(预先体验版)
2006/11/07 Javascript
input的focus方法使用
2010/03/13 Javascript
ExtJs 表单提交登陆实现代码
2010/08/19 Javascript
Javascript在IE和FireFox中的不同表现简析
2012/12/03 Javascript
Function.prototype.call.apply结合用法分析示例
2013/07/03 Javascript
JS小功能(操作Table--动态添加删除表格及数据)实现代码
2013/11/28 Javascript
javascript中数组的冒泡排序使用示例
2013/12/18 Javascript
js给页面加style无效果的解决方法
2014/01/20 Javascript
浅析Node在构建超媒体API中的作用
2014/07/30 Javascript
jQuery中replaceAll()方法用法实例
2015/01/16 Javascript
JavaScript编程中容易出BUG的几点小知识
2015/01/31 Javascript
基于javascript代码检测访问网页的浏览器呈现引擎、平台、Windows操作系统、移动设备和游戏系统
2015/12/03 Javascript
不用一句js代码初始化组件
2016/01/27 Javascript
基于Layer+jQuery的自定义弹框
2020/05/26 Javascript
JS定时器实现数值从0到10来回变化
2016/12/09 Javascript
微信小程序 获取javascript 里的数据
2017/08/17 Javascript
VUE解决微信签名及SPA微信invalid signature问题(完美处理)
2019/03/29 Javascript
JavaScript实现星级评价效果
2019/05/17 Javascript
JavaScript实现旋转木马轮播图
2020/03/16 Javascript
[00:55]2015国际邀请赛中国区预选赛5月23日——28日约战上海
2015/05/25 DOTA
Python解析nginx日志文件
2015/05/11 Python
Python实现读取json文件到excel表
2017/11/18 Python
python编写暴力破解zip文档程序的实例讲解
2018/04/24 Python
python 内置函数汇总详解
2019/09/16 Python
英国在线药房和在线医生:LloydsPharmacy
2019/10/21 全球购物
苏格兰领先的多渠道鞋店:Begg Shoes
2019/10/22 全球购物
美国职棒大联盟的官方手套、球和头盔:Rawlings
2020/02/15 全球购物
什么叫应用程序域?什么是托管代码?什么是强类型系统?什么是装箱和拆箱?什么是重载?CTS、CLS和CLR分别作何解释?
2012/05/23 面试题
幼儿教师自我鉴定
2013/11/02 职场文书
心理学专业大学生职业生涯规划范文
2014/02/19 职场文书
高中校园广播稿3篇
2014/09/29 职场文书
golang中切片copy复制和等号复制的区别介绍
2021/04/27 Golang
Django+Nginx+uWSGI 定时任务的实现方法
2022/01/22 Python