详解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中的控制流语句的知识点
Apr 14 Python
Python实现给qq邮箱发送邮件的方法
May 28 Python
Python实现将绝对URL替换成相对URL的方法
Jun 28 Python
Django 添加静态文件的两种实现方法(必看篇)
Jul 14 Python
Python实现的递归神经网络简单示例
Aug 11 Python
在windows下使用python进行串口通讯的方法
Jul 02 Python
浅谈Pytorch中的torch.gather函数的含义
Aug 18 Python
Python浮点数四舍五入问题的分析与解决方法
Nov 19 Python
Python中类似于jquery的pyquery库用法分析
Dec 02 Python
python GUI库图形界面开发之PyQt5信号与槽的高级使用技巧(自定义信号与槽)详解与实例
Mar 06 Python
Python3实现英文字母转换哥特式字体实例代码
Sep 01 Python
教你怎么用Python监控愉客行车程
Apr 29 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
人工智能开始玩《星际争霸2》 你的操作跟得上吗?
2017/08/11 星际争霸
php的一个登录的类 [推荐]
2007/03/16 PHP
php格式化日期和时间格式化示例分享
2014/02/24 PHP
PHP中判断文件存在使用is_file还是file_exists?
2015/04/03 PHP
PHP实现无限分类的实现方法
2016/11/14 PHP
JavaScript中的16进制字符(改进)
2011/11/21 Javascript
js判断输入是否为数字的具体实例
2013/08/03 Javascript
浅谈 javascript 事件处理
2015/01/04 Javascript
javascript字符串与数组转换汇总
2015/05/26 Javascript
原生JavaScript实现瀑布流布局
2020/06/28 Javascript
JS中使用apply方法通过不同数量的参数调用函数的方法
2016/05/31 Javascript
浅谈bootstrap使用中的一些问题以及解决过程
2016/10/18 Javascript
js实现鼠标左右移动,图片也跟着移动效果
2017/01/25 Javascript
ES6新特性之模块Module用法详解
2017/04/01 Javascript
详解vue-router 2.0 常用基础知识点之导航钩子
2017/05/10 Javascript
用js实现before和after伪类的样式修改的示例代码
2017/09/07 Javascript
深入理解Node module模块
2018/03/26 Javascript
Element-ui DatePicker显示周数的方法示例
2019/07/19 Javascript
Vue.js项目实战之多语种网站的功能实现(租车)
2019/08/07 Javascript
微信公众号H5之微信分享常见错误和问题(小结)
2019/11/14 Javascript
解决vue-loader加载不上的问题
2020/10/21 Javascript
[02:16]卖萌的僵尸 DOTA2神话信使飞僵小宝来袭
2014/03/24 DOTA
Python 错误和异常小结
2013/10/09 Python
Python生成随机数的方法
2014/01/14 Python
Python ORM框架SQLAlchemy学习笔记之关系映射实例
2014/06/10 Python
Python全局变量与局部变量区别及用法分析
2018/09/03 Python
Python实现登陆文件验证方法
2018/10/06 Python
Python+Tensorflow+CNN实现车牌识别的示例代码
2019/10/11 Python
解决pycharm安装第三方库失败的问题
2020/05/09 Python
自定义Django_rest_framework_jwt登陆错误返回的解决
2020/10/18 Python
详解Html5原生拖拽操作
2018/01/12 HTML / CSS
G-Form护具官方网站:美国运动保护装备
2019/09/04 全球购物
高中生活自我鉴定
2014/01/18 职场文书
导游词范文之颐和园/重庆/云台山
2019/09/10 职场文书
redis 存储对象的方法对比分析
2021/08/02 Redis
本地搭建minio文件服务器(使用bat脚本启动)的方法
2022/07/15 Servers