编码

一:编码

无论在py2还是py3里面,编码的问题都是很重要的,因为目前来看,还是py2位主流,所以下面简单说一下我对编码的理解。

编码:

基本概念很简单。首先,我们从一段信息即消息说起,消息以人类可以理解、易懂的表示存在。
我打算将这种表示称为“明文”(plain text)。对于说英语的人,纸张上打印的或屏幕上显示的英文单词都算作明文。 其次,我们需要能将明文表示的消息转成另外某种表示,我们还需要能将编码文本转回成明文。
从明文到编码文本的转换称为“编码”,从编码文本又转回成明文则为“解码”。

首先我们在pycharm中,建立一个text或者其他类型的文件,里面写入任何内容,这时候里面的内容不是保存在内存中,是已经保存在了磁盘中,

首先说在py2中的编码问题

1:  str:bytes                                           打个比方

s = "你好"
print len(s)
s = "你好hello"
print len
print type(s) 结果显示是6 11 str

unicode:unicode

# unicode: unicode
# s=u'袁浩hello'
# print repr(s)#u'\u8881\u6d69hello'
# print type(s)#unicode
str和unicode

str和unicode都是basestring的子类。严格意义上说,str其实是字节串,它是unicode经过编码后的字节组成的序列。对UTF-8编码的str''使用len()函数时,结果是3,因为utf8编码的'' == '\xe8\x8b\x91'。

而unicode是一个字符串,str是unicode这个字符串经过编码(utf8,gbk等)后的字节组成的序列。如上面utf8编码的字符串''。

unicode才是真正意义上的字符串,对字节串str使用正确的字符编码进行解码后获得,并且len(u'') == 1。

在Py2里,str=bytes。

py2编码的最大特点是Python 2 将会自动的将bytes数据解码成 unicode 字符串

所以在2里我们可以将字节与字符串拼接。

来看一些代码

#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)

2.   py3里面

跟 Python 2 类似,Python 3 也有两种类型,一个是 Unicode,一个是 byte 码。但是他们有不同的命名。   

现在你从普通文本转换成 “str” 类型后存储的是一个 unicode, “bytes” 类型存储的是 byte 串。你也可以通过一个 b 前缀来制造 byte 串。

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

Python 3 中对 Unicode 支持的最大变化就是将会没有对 byte 字节串的自动解码。如果你想要用一个 byte 字节串和一个 unicode 相链接的话,你将会得到一个错误,不管你包含的内容是什么。

所有这些在 Python 2 中都将会有隐式的处理,而在 Python 3 中你将会得到一个错误。

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

s='苑昊'
print(json.dumps(s))   #"\u82d1\u660a"
b1=s.encode('utf8')

print(b1,type(b1))     #b'\xe8\x8b\x91\xe6\x98\x8a' <class 'bytes'>

print(b1.decode('utf8'))#苑昊
# print(b1.decode('gbk'))# 鑻戞槉

b2=s.encode('gbk')
print(b2,type(b2))  #'\xd4\xb7\xea\xbb' <class 'bytes'>
print(b2.decode('gbk')) #苑昊

3.编码的实现

3.1首先 来看一下 默认编码

什么是默认编码?其实就是你的解释器解释代码时默认的编码方式,在py2里默认的编码方式是ASCII,在py3里则是utf8(sys.getdefaultencoding()查看)。

1
#-*- coding: UTF-8 -*-
这个声明是做什么的?我们在最开始只知道在py2里如果不加上这么一句话,程序一旦出现中文就会报错,其实就是因为py2默认的ASCII码,对于中文这些特殊字符无法编码;

声明这句话就是告诉python2.7解释器 (默认ACSII编码方式)解释hello.py文件声明下面的内容按utf8编码,对,就是编码(编码成字节串最后转成0101的形式让机器去执行) 

大家注意hello.py文件保存时有自己特定的编码方式,比如utf8,比如gbk。

需要注意的是声明的编码必须与文件实际保存时用的编码一致,否则很大几率会出现代码解析异常。现在的IDE一般会自动处理这种情况,改变声明后同时换成声明的编码保存,但文本编辑器控们需要小心。所以,保存的编码样式取决于你的编辑器默认的样式(可调)。

3.2    文件的保存和执行过程

我们讲过,字符串在内存中是以unicode的数据形式保存的,可什么时候我们数据是在内存呢?让我们一起解析这个过程

比如我们在pycharm上(py3.5)创建一个hello.py文件:

1
print('hello 苑昊')
这个时候我们的数据在内存吗?NO,它已经被pycharm以默认的文件保存编码方式存到了硬盘(二进制数据),所以一定注意,你点击运行的时候,其实首先需要打开这个文件,然后将所有的数据转移到内存,字符串此时就以unicode的数据格式存到内存的某块地址上(为什么要这样处理一会讲到),其它内容还是utf8的编码方式,然后解释器就可以按着默认的utf8的编码方式逐行解释了。 

所以,一旦你的文件保存时的编码与解释器解释的编码不一致时就会出现错误。

以上是我对编码的简单理解,当然其中还有一些借鉴的东西,最后在加上一个图来使大家更为详细的了解一下编码

 

 

 

 

 

 

 

 

 

 

posted @ 2016-10-14 17:53  Marsasang  阅读(222)  评论(0编辑  收藏  举报