python与编码

编码的概念

  学习python已经半年了,回过头来看编码问题,发现它在我们学习过程中埋了很多雷,不完全搞懂python的编码在学习python的过程中还埋着很多潜在的雷呢。

文件从磁盘到内存的编码

  首先,抛开python解释器来说,就一般的应用程序(记事本等)来说,你写的文字还没有保存的时候是以什么形式存在在内存的呢?

  是Unicode二进制数据,他是内存编码的一种规范,实际上Unicode编码方式完全解决了全世界的文字编码问题,只是在将内存数据存储到硬盘的时候,Unicode数据占用空间要远大于utf8(编写代码,中文数据出现频率很低),当硬盘不变时,utf8的数据占空间更小,传输更快,所以utf解决了保存和传输数据的问题。

  所以,我们保存在磁盘上的数据是什么类型的?

  答案是通过某种编码方式编码的bytes字节串。由于历史遗留问题,在utf8之前还有gbk等一些字符编码方式存在。

    最早的时候计算机使用的编码规则是ASCII码,ASCII码最早是美国人使用的。ASCII码用一个字节的二进制组来表示一个字符(因为他们只用到26个引文字母和一些符号,最初的ASCII码甚至只用到7个bit位)。

    随着计算机的日益普及,ASCII码难以满足世界各地人们的使用,在中国就出现了GB2312与GBK的编码方式,使用两个字节的二进制组表示一个字符(甚至强硬的占用了拉美等国家的最高bit位)。正因为如此,世界各地都使用自己的编码方式,各自的软件都无法兼容了,所以就出现了万国码。

    万国码(Unicode)覆盖了全世界所有的文字,这也太强大了,那我们使用万国码不是很方便吗?但是对于美国人来说,他们只需要使用一个字节就可以表示所有的字符,而现在却平白无故多出一个字节,这使得内存与硬盘浪费了空间,所以Unicode优化成了现在的utf-8格式。utf-8是可变长的编码方式,所以现在开发倾向于使用这种编码方式。但是现在依然很多地方在使用GBK,ASCII等编码方式,所以对于编码我们需要详细的了解。

  回到应用程序上来,当我们执行保存文件的时候,应用程序有默认的编码方式将内存中的Unicode二进制数编码成bytes类型存储到硬盘,当我们再次打开应用程序的时候,它又以同样的编码方式将硬盘上的bytes数据解码成Unicode数据存放到内存,我们就可以以明文方式看到数据了。

  utf8这么好为什么我们内存中不使用utf8格式存放呢,一句话就是utf8不能直接转换成gbk等其他数据,但是Unicode可以直接编码成gbk等格式数据。

  Unicode与utf8的关系:

  Unicode是内存编码表示方案(是规范),而UTF是如何保存和传输Unicode的方案(是实现)这也是UTF与Unicode的区别。

  Unicode进行明文与二进制之间的转换,utf8进行二进制与二进制之间的数据转换打印unicode数据就会显示相应的明文(包括英文和中文)。

  python解释器与我们上面说的记事本程序的数据编码解码很类似。

  当我们保存的的时候,文件就以pycharm默认的编码方式保存到了磁盘;关闭文件后再打开,pycharm就再以默认的编码方式对该文件打开后读到的内容进行解码,转成unicode到内存我们就看到了我们的明文;(这个过程使用记事本也可以完成,在cmd中完成运行)

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

  以上就是完整的文件的编码,我们下面讲的python2与python3的字符串编码是在cpu执行程序时的存储状态,是另外一个过程,不要混淆!

python2的string编码

    python2中默认编码方式是ASCII码。

name = '杰夫'     #str类型为bytes
name2 = u'杰夫'   #将字符串类型改为Unicode
print  repr(name)
print  repr(name2)


运行结果
'\xbd\xdc\xb7\xf2'
u'\u6770\u592b'

    在python2中str字符串类型在内存中存的是bytes类型,Unicode类型字符串存储的是Unicode数据。

    

name = '杰夫'                #name为字节数据类型
name2 = u'杰夫'            #name为unicode数据类型
name3 = name.decode('utf8')
name4 = name2.encode('utf8')
print type(name3)
print type(name4)
print repr(name)
print repr(name2)
print repr(name3)
print repr(name4)
运行结果
<type 'unicode'>
<type 'str'>
'\xe6\x9d\xb0\xe5\xa4\xab'  #str字符串类型的bytes数据
u'\u6770\u592b'             #Unicode字符串类型的Unicode数据
u'\u6770\u592b'             #str字符串类型解码成Unicode数据
'\xe6\x9d\xb0\xe5\xa4\xab'  #Unicode字符串类型编码成bytes数据

python3的string编码

    python3中默认的编码方式是utf-8.

name = b'jeff'
name2 = '杰夫'
print(type(name))
print(repr(name))
print(type(name2))
print(repr(name2))
运行结果
<class 'bytes'>
b'jeff'
<class 'str'>
'杰夫'

    python3中str字符串类型在内存中存的是Unicode数据,bytes类型字符串存储的是bytes数据。

name = b'jeff'
name2 = '杰夫'
name3=name.decode('utf8')
name4=name2.encode('utf8')
print(type(name))
print(type(name2))
print(type(name3))
print(type(name4))
print(repr(name))
print(repr(name2))
print(repr(name3))
print(repr(name4))
运行结果
<class 'bytes'>
<class 'str'>
<class 'str'>
<class 'bytes'>
b'jeff'                         #bytes类型字符串存储的bytes数据
'杰夫'                           #str类型字符串存储的Unicode数据
'jeff' #bytes类型字符串解码成Unicode数据 b'\xe6\x9d\xb0\xe5\xa4\xab' #str类型字符串编码城bytes数据

    简单的总结一下编码bytes数据是为了方便传输与存储,而Unicode数据方便了显示,python3比python2更加清晰化了字节与字符的界限,python3取消了python2中的不同类型字符串的拼接。

    因为编码方式的不同经常会出现下面这种情况。

    在python中写一个小程序,

#coding=utf8
print('杰夫')

  在windows终端打开此文件。

这里显示出一堆乱码,这是为什么呢?

因为我的python3默认编码方式是utf-8,而我的windows终端默认解码方式是GBK,lianxi1.py这个文件内容在内存中以utf-8的编码方式写入硬盘,在cmd中执行时,cmd软件默认解码方式是GBK,用GBK的方式去解码utf-8的二进制数据,解码出来的就是一堆乱码,所以解决方法就是要么让cmd使用utf-8的方式来解码,否则就只能让python解释器用GBK方式将文件内容编码存入硬盘。

#coding=GBK
print('杰夫')

   http://www.cnblogs.com/yuanchenqi/p/5956943.html苑昊老师的博客里对于字符编码的详细解释写的非常棒,可以进行进一步参考。

posted @ 2017-07-02 14:10  JeffD  阅读(318)  评论(1编辑  收藏  举报