**转载网址**:https://www.cnblogs.com/575dsj/p/7112767.html

py编码终极版

说起python编码,真是句句心酸。算起来,反复折腾两个来月了。万幸的是,终于梳理清楚了。作为一个共产主义者,一定要分享给大家。如果你还在因为编码而头痛,那么赶紧跟着我咱们一起来揭开py编码的真相吧!

一 什么是编码?

基本概念很简单。首先,我们从一段信息即消息说起,消息以人类可以理解、易懂的表示存在。我打算将这种表示称为“明文”(plain text)。对于说英语的人,纸张上打印的或屏幕上显示的英文单词都算作明文。

其次,我们需要能将明文表示的消息转成另外某种表示,我们还需要能将编码文本转回成明文。从明文到编码文本的转换称为“编码”,从编码文本又转回成明文则为“解码”。

编码问题是个大问题,如果不彻底解决,它就会像隐藏在丛林中的小蛇,时不时地咬你一口。那么到底什么是编码呢?//ASCII记住一句话:计算机中的所有数据,不论是文字、图片、视频、还是音频文件,本质上最终都是按照类似 01010101 的二进制存储的。    再说简单点,计算机只懂二进制数字!所以,目的明确了:如何将我们能识别的符号唯一的与一组二进制数字对应上?于是美利坚的同志想到通过一个电平的高低状态来代指0或1,    八个电平做为一组就可以表示出256种不同状态,每种状态就唯一对应一个字符,比如A--->00010001,而英文只有26个字符,算上一些特殊字符和数字,128个状态也够    用了;每个电平称为一个比特为,约定8个比特位构成一个字节,这样计算机就可以用127个不同字节来存储英语的文字了。这就是ASCII编码。扩展ANSI编码刚才说了,最开始,一个字节有八位,但是最高位没用上,默认为0;后来为了计算机也可以表示拉丁文,就将最后一位也用上了,从128到255的字符集对应拉丁文啦。至此,一个字节就用满了!//GB2312计算机漂洋过海来到中国后,问题来了,计算机不认识中文,当然也没法显示中文;而且一个字节所有状态都被占满了,万恶的帝国主义亡    我之心不死啊!我党也是棒,自力更生,自己重写一张表,直接生猛地将扩展的第八位对应拉丁文全部删掉,规定一个小于127的字符的意    义与原来相同,但两个大于127的字符连在一起时,就表示一个汉字,前面的一个字节(他称之为高字节)从0xA1用到0xF7,后面一个字节   (低字节)从0xA1到0xFE,这样我们就可以组合出大约7000多个简体汉字了;这种汉字方案叫做 “GB2312”。GB2312 是对 ASCII 的中文扩展。//GBK 和 GB18030编码但是汉字太多了,GB2312也不够用,于是规定:只要第一个字节是大于127就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的    内容。结果扩展之后的编码方案被称为 GBK 标准,GBK 包括了 GB2312 的所有内容,同时又增加了近20000个新的汉字(包括繁体字)和符号。//UNICODE编码:很多其它国家都搞出自己的编码标准,彼此间却相互不支持。这就带来了很多问题。于是,国际标谁化组织为了统一编码:提出了标准编码准    则:UNICODE 。UNICODE是用两个字节来表示为一个字符,它总共可以组合出65535不同的字符,这足以覆盖世界上所有符号(包括甲骨文)//utf8:unicode都一统天下了,为什么还要有一个utf8的编码呢?大家想,对于英文世界的人们来讲,一个字节完全够了,比如要存储A,本来00010001就可以了,现在吃上了unicode的大锅饭,得用两个字节:00000000 00010001才行,浪费太严重!基于此,美利坚的科学家们提出了天才的想法:utf8.UTF-8(8-bit Unicode Transformation Format)是一种针对Unicode的可变长度字符编码,它可以使用1~4个字节表示一个符号,根据    不同的符号而变化字节长度,当字符在ASCII码的范围时,就用一个字节表示,所以是兼容ASCII编码的。这样显著的好处是,虽然在我们内存中的数据都是unicode,但当数据要保存到磁盘或者用于网络传输时,直接使用unicode就远不如utf8省空间啦!这也是为什么utf8是我们的推荐编码方式。Unicode与utf8的关系:一言以蔽之:Unicode是内存编码表示方案(是规范),而UTF是如何保存和传输Unicode的方案(是实现)这也是UTF与Unicode的区别。

补充:utf8是如何节约硬盘和流量的

1
s="I'm 苑昊"

你看到的unicode字符集是这样的编码表:

I  0049
'  0027
m  006d0020
苑 82d1
昊 660a

每一个字符对应一个十六进制数字。
计算机只懂二进制,因此,严格按照unicode的方式(UCS-2),应该这样存储:

I      00000000 01001001
'      00000000 00100111
m      00000000 0110110100000000 00100000
苑     10000010 11010001
昊     01100110 00001010

这个字符串总共占用了12个字节,但是对比中英文的二进制码,可以发现,英文前9位都是0!浪费啊,浪费硬盘,浪费流量。怎么办?UTF8:

I    01001001
'    00100111
m    0110110100100000
苑   11101000 10001011 10010001
昊   11100110 10011000 10001010

utf8用了10个字节,对比unicode,少了两个,因为我们的程序英文会远多于中文,所以空间会提高很多!

记住:一切都是为了节省你的硬盘和流量。  

二 py2的string编码

在py2中,有两种字符串类型:str类型和unicode类型;注意,这仅仅是两个名字,python定义的两个名字,关键是这两种数据类型在程序运行时存在内存地址的是什么?

我们来看一下:

1
2
3
4
5
6
7
8
9
10
#coding:utf8
s1='苑'
print type(s1) # <type 'str'>
print repr(s1) #'\xe8\x8b\x91
s2=u'苑'
print type(s2) # <type 'unicode'>
print repr(s2) # u'\u82d1'

内置函数repr可以帮我们在这里显示存储内容。原来,str和unicode分别存的是字节数据和unicode数据;那么两种数据之间是什么关心呢?如何转换呢?这里就涉及到编码(encode)和解码(decode)了

s1=u’苑’
print repr(s1) #u’\u82d1’

b=s1.encode(‘utf8’)
print b
print type(b) #<type ‘str’>
print repr(b) #’\xe8\x8b\x91’

s2=’苑昊’
u=s2.decode(‘utf8’)
print u # 苑昊
print type(u) # <type ‘unicode’>
print repr(u) # u’\u82d1\u660a’

#注意 u2=s2.decode(‘gbk’) print u2 #鑻戞槉 print len(‘苑昊’) #6

无论是utf8还是gbk都只是一种编码规则,一种把unicode数据编码成字节数据的规则,所以utf8编码的字节一定要用utf8的规则解码,否则就会出现乱码或者报错的情况。

py2编码的特色:

1
2
3
4
5
6
7
8
9
#coding:utf8
print '苑昊' #  苑昊   
print repr('苑昊')#'\xe8\x8b\x91\xe6\x98\x8a'
print (u"hello"+"yuan")
#print (u'苑昊'+'最帅')   #UnicodeDecodeError: 'ascii' codec can't decode byte 0xe6
                         # in position 0: ordinal not in range(128)

Python 2 悄悄掩盖掉了 byte 到 unicode 的转换,只要数据全部是 ASCII 的话,所有的转换都是正确的,一旦一个非 ASCII 字符偷偷进入你的程序,那么默认的解码将会失效,从而造成 UnicodeDecodeError 的错误。py2编码让程序在处理 ASCII 的时候更加简单。你复出的代价就是在处理非 ASCII 的时候将会失败。

三 py3的string编码

python3 renamed the unicode type to str ,the old str type has been replaced by bytes.

py3也有两种数据类型:str和bytes;  str类型存unicode数据,bytse类型存bytes数据,与py2比只是换了一下名字而已。

import jsons='苑昊'
print(type(s))       #<class 'str'>
print(json.dumps(s)) #  "\u82d1\u660a"b=s.encode('utf8')
print(type(b))      # <class 'bytes'>
print(b)            # b'\xe8\x8b\x91\xe6\x98\x8a'u=b.decode('utf8')
print(type(u))       #<class 'str'>
print(u)             #苑昊
print(json.dumps(u)) #"\u82d1\u660a"print(len('苑昊')) # 2

py3的编码哲学:

Python 3最重要的新特性大概要算是对文本和二进制数据作了更为清晰的区分,不再会对bytes字节串进行自动解码。文本总是Unicode,由str类型表示,二进制数据则由bytes类型表示。Python 3不会以任意隐式的方式混用str和bytes,正是这使得两者的区分特别清晰。你不能拼接字符串和字节包,也无法在字节包里搜索字符串(反之亦然),也不能将字符串传入参数为字节包的函数(反之亦然)。

1
2
#print('alvin'+u'yuan')#字节串和unicode连接 py2:alvinyuan
print(b'alvin'+'yuan')#字节串和unicode连接 py3:报错 can't concat bytes to str

注意:无论py2,还是py3,与明文直接对应的就是unicode数据,打印unicode数据就会显示相应的明文(包括英文和中文)

四 文件从磁盘到内存的编码(******)

说到这,才来到我们的重点!

抛开执行执行程序,请问大家,文本编辑器大家都是用过吧,如果不懂是什么,那么word总用过吧,ok,当我们在word上编辑文字的时候,不管是中文还是英文,计算机都是不认识的,那么在保存之前数据是通过什么形式存在内存的呢?yes,就是unicode数据,为什么要存unicode数据,这是因为它的名字最屌:万国码!解释起来就是无论英文,中文,日文,拉丁文,世界上的任何字符它都有唯一编码对应,所以兼容性是最好的。

好,那当我们保存了存到磁盘上的数据又是什么呢?

答案是通过某种编码方式编码的bytes字节串。比如utf8---一种可变长编码,很好的节省了空间;当然还有历史产物的gbk编码等等。于是,在我们的文本编辑器软件都有默认的保存文件的编码方式,比如utf8,比如gbk。当我们点击保存的时候,这些编辑软件已经”默默地”帮我们做了编码工作。

那当我们再打开这个文件时,软件又默默地给我们做了解码的工作,将数据再解码成unicode,然后就可以呈现明文给用户了!所以,unicode是离用户更近的数据,bytes是离计算机更近的数据。

说了这么多,和我们程序执行有什么关系呢?

先明确一个概念:py解释器本身就是一个软件,一个类似于文本编辑器一样的软件!

现在让我们一起还原一个py文件从创建到执行的编码过程:

打开pycharm,创建hello.py文件,写入

ret=1+1
s='苑昊'
print(s)

当我们保存的的时候,hello.py文件就以pycharm默认的编码方式保存到了磁盘;关闭文件后再打开,pycharm就再以默认的编码方式对该文件打开后读到的内容进行解码,转成unicode到内存我们就看到了我们的明文;

而如果我们点击运行按钮或者在命令行运行该文件时,py解释器这个软件就会被调用,打开文件,然后解码存在磁盘上的bytes数据成unicode数据,这个过程和编辑器是一样的,不同的是解释器会再将这些unicode数据翻译成C代码再转成二进制的数据流,最后通过控制操作系统调用cpu来执行这些二进制数据,整个过程才算结束。

那么问题来了,我们的文本编辑器有自己默认的编码解码方式,我们的解释器有吗?

当然有啦,py2默认ASCII码,py3默认的utf8,可以通过如下方式查询

1
2
import sys
print(sys.getdefaultencoding())

大家还记得这个声明吗?

1
#coding:utf8

是的,这就是因为如果py2解释器去执行一个utf8编码的文件,就会以默认地ASCII去解码utf8,一旦程序中有中文,自然就解码错误了,所以我们在文件开头位置声明 #coding:utf8,其实就是告诉解释器,你不要以默认的编码方式去解码这个文件,而是以utf8来解码。而py3的解释器因为默认utf8编码,所以就方便很多了。

注意:我们上面讲的string编码是在cpu执行程序时的存储状态,是另外一个过程,不要混淆!

五 常见的编码问题

1 cmd下的乱码问题

hello.py

1
2
#coding:utf8
print ('苑昊')

文件保存时的编码也为utf8。

思考:为什么在IDE下用2或3执行都没问题,在cmd.exe下3正确,2乱码呢?

我们在win下的终端即cmd.exe去执行,大家注意,cmd.exe本身也一个软件;当我们python2 hello.py时,python2解释器(默认ASCII编码)去按声明的utf8编码文件,而文件又是utf8保存的,所以没问题;问题出在当我们print’苑昊’时,解释器这边正常执行,也不会报错,只是print的内容会传递给cmd.exe用来显示,而在py2里这个内容就是utf8编码的字节数据,可这个软件默认的编码解码方式是GBK,所以cmd.exe用GBK的解码方式去解码utf8自然会乱码。

py3正确的原因是传递给cmd的是unicode数据,cmd.exe可以识别内容,所以显示没问题。

明白原理了,修改就有很多方式,比如:

1
print (u'苑昊')

改成这样后,cmd下用2也不会有问题了。

2 open()中的编码问题

创建一个hello文本,保存成utf8:

苑昊,你最帅!

同目录下创建一个index.py

f=open('hello')
print(f.read())

为什么 在linux下,结果正常:苑昊,在win下,乱码:鑻戞槉(py3解释器)?

因为你的win的操作系统安装时是默认的gbk编码,而linux操作系统默认的是utf8编码;

当执行open函数时,调用的是操作系统打开文件,操作系统用默认的gbk编码去解码utf8的文件,自然乱码。

解决办法:

f=open('hello',encoding='utf8')
print(f.read())

如果你的文件保存的是gbk编码,在win 下就不用指定encoding了。

另外,如果你的win上不需要指定给操作系统encoding=’utf8’,那就是你安装时就是默认的utf8编码或者已经通过命令修改成了utf8编码。

注意:open这个函数在py2里和py3中是不同的,py3中有了一个encoding=None参数。

python编码终极版相关推荐

  1. py编码终极版(yuan)

    py编码终极版 一 什么是编码? 基本概念很简单.首先,我们从一段信息即消息说起,消息以人类可以理解.易懂的表示存在.我打算将这种表示称为"明文"(plain text).对于说英 ...

  2. Python 装饰器记录总结 (终极版)

    Python 装饰器记录总结 (终极版) 原文链接:http://magicroc.com/2017/04/10/Python装饰器记录总结/ 装饰器是一个函数,一个用来包装函数的函数,装饰器在函数申 ...

  3. matlab 30案例 目录,MATLAB-智能算法30个案例分析-终极版(带目录).doc

    MATLAB-智能算法30个案例分析-终极版(带目录) MATLAB 智能算法30个案例分析(终极版) 1?基于遗传算法的TSP算法(王辉)? 2?基于遗传算法和非线性规划的函数寻优算法(史峰)? 3 ...

  4. python手机编译器推荐_Python编译器最新版|Python编译器手机版下载 v1.2 安卓版 - 数码资源网...

    现在互联网发展迅速发展,很多人开始往it行业发展,我给你们推荐一款很好的软件,Python编译器手机版主要为Python初学者提供直接运行的功能,能够随手验证一些小程序,Python编译器app支持直 ...

  5. Python PEP8-中文版-全文(1)

    Python PEP8-中文版-全文(1) PEP 8--Python代码风格指南 PEP: 8 标题:Python代码风格指南 版本:c451868df657 Last-Modified: 2016 ...

  6. EasyCode的Mybatis终极版模板

    EasyCode的Mybatis终极版 距离我第一次上手EasyCode已经有一年的时间 提醒一下,看这篇文章,如果你已经有EasyCode使用基础,只是来拿一下模板,可以直接看,如果你同时想知道知道 ...

  7. python3 购物车 增改查终极版~

    还是先来条NLP再说,快没了,以后想抄还没有... 十一,没有挫败,只有回应讯息 "挫败"只是指出过去的做法得不到预期的效果,是给我们需要改变的信号. "挫败" ...

  8. 阿里巴巴Java开发手册终极版网页版v1.3.0

    前言 一 .编程规约 ( 一 ) 命名风格 ( 二 ) 常量定义 ( 三 ) 代码格式 ( 四 ) OOP规约 ( 五 ) 集合处理 ( 六 ) 并发处理 ( 七 ) 控制语句 ( 八 ) 注释规约 ...

  9. python安卓程序,python软件安卓版

    大家好,小编来为大家解答以下问题,python3安卓版下载,python软件安卓版,现在让我们一起来看看吧! 1.如何用手机编程Python? 1.QPython3:这是一个在上运行python3的脚 ...

最新文章

  1. mysql单列索引和多列索引_mysql 单列索引与多列索引
  2. Spring boot显示登录用户
  3. Linux centos7安装Git及 Jenkins配置Git
  4. Spring Cloud配置–外部化应用程序配置
  5. 前端进阶试题-CSS篇
  6. word把选择答案弄到题目里_一个极限案例弄明白为何“看答案都明白,做题目就是想不起来”...
  7. 实例:评审速度与缺陷密度之间的相关性
  8. 树的先序遍历递归的理解
  9. Android调用系统相册、拍照以及裁剪最简单的实现(兼容7.0)
  10. printline在C语言中的作用,iswprint - [ C语言中文开发手册 ] - 在线原生手册 - php中文网...
  11. 用maven骨架新建项目以及解决速度慢的问题
  12. AVI视频怎么转换成MOV视频
  13. c++ CImage类的常用命令
  14. 恐龙涂色游戏 - 恐龙画画世界填色游戏
  15. Excel大家来找茬,两列数据对比找出不同数据
  16. hp proliant DL360p Gen8风扇故障排除
  17. C措辞教程第四章: 数组(8)
  18. python爬取QQ音乐免费歌曲 2020.7.26
  19. c加加中print是什么意思_数学中质数和合数是什么意思
  20. 二级域名做网站有哪些优势?

热门文章

  1. Django 自定义404页面
  2. 从源码的角度看Go语言flag库如何解析命令行参数!
  3. 怎么用pe安装服务器系统安装系统,pe下安装服务器系统安装教程
  4. android创建文件夹、文件file读、写内容
  5. 计算机网络课程设计——中小型网络工程设计与实现
  6. 职中计算机网络基础期中考试试卷答案,中职计算机网络基础期中试卷
  7. R安装程辑包,无法打开压缩文件错误
  8. 搜狗SEO优化搜狗权重域名快速收录
  9. bed文件格式(转自http://blog.sina.com.cn/s/blog_70b2b6020100liou.html)
  10. 正则匹配yyyy-MM-dd HH:mm:ss