python2和python3编码问题【encode和decode】
https://www.cnblogs.com/liaohuiqiang/p/7247393.html
- 概述
# 1
# coding:utf-8 # 开头的encoding是对于文件内容的编码
# 2
import sys
reload(sys)
sys.setdefaultencoding('utf8') # python方法中默认使用的编码
s = '字节串str'
s.encode('utf8')
#等价于
s.decode(系统编码).encode('utf8')
- python2.7中的字符串一般有两种类型,unicode和str。
str为字节码,会根据某种编码把字符串转成一个个字节,这个时候字符和字节没有所谓固定的一一对应的关系。
unicode则是用unicode编码的字符串,这个时候一个字符是对应两个字节的,一一对应。直接赋值字符串,类型为str,str为字节串,会按照开头的encoding来编码成一个个的字节。
赋值的时候在字符串前面加个u,类型则为unicode,直接按照unicode来编码。
s1 = '字节串'
print type(s1) #输出 <type 'str'>,按照开头的encoding来编码成相应的字节。
print len(s1) #输出9,因为按utf8编码,一个汉字占3个字节,3个字就占9个字节。
s2 = u'统一码'
print type(s2) #输出 <type 'unicode'>,用unicode编码,2个字节1个字符。
print len(s2) #输出3,unicode用字符个数来算长度,从这个角度上看,unicode才是真正意义上的字符串类型
s = '机器学习'
s[-2:] == '学习‘
# 返回false,平时写程序可能会以为相等。
# 这里的”学习是用开头的encoding声明解释的,我开头用的是utf8,汉字占3个字节,所以“学习”占了6个字节),而s[-2:]取的是最后两个”双字节“,所以不相同。
s = u'机器学习'
s[-2:] == u'学习’
# 返回true,这也是为什么说unicode是真正意义上的字符串类型。因为使用的是unicode,”学习“占的是两个”双字节“,一个"双字节“一个字
- python2.7中的【encode和decode】
encode的正常使用:对unicode类型进行encode,得到字节串str类型。也即是unicode -> encode(根据指定编码) -> str【encode结果】。
decode的正常使用:对str类型进行decode,得到unicode类型。 也即是str -> decode(根据指定编码) -> unicode【decode结果】。
s3 = u'统一码'.encode('utf8')
print type(s3) # 输出 <type 'str'>
s4 = '字节串'.decode('utf8')
print type(s4) #输出 <type 'unicode'>
- encode和decode的不正常使用
encode的不正常使用:对str类型进行encode,因为encode需要的是unicode类型,这个时候python会用默认的系统编码decode成unicode类型,再用你给出编码进行encode。
decode的不正常使用:对unicode类型进行decode,python会用默认的系统编码encode成str类型,再用你给出的编码进行decode。
所以改好对应的系统默认编码,就算不正常使用,也不会报错。
修改系统默认编码
系统默认使用ascii编码,需要进行相应的修改。这个编码和开头的encoding不同之处在于,开头的encoding是对于文件内容的编码。
这里的编码是一些python方法中默认使用的编码,比如对str进行encode的时候默认先decode的编码,比如文件写操作write的encode的编码
import sys
reload(sys)
sys.setdefaultencoding('utf8')
s = '字节串str'
s.encode('utf8')
#等价于
s.decode(系统编码).encode('utf8')
import sys
print sys.getdefaultencoding() # 输出ascii
s = u'华南理工大学'
print type('大学') # str
print type(s[-2:]) # unicode
print s[-2:] == '大学' # 返回False,并有warning提醒 # python在用==比较时,如果第一个操作符是unicode而第二个不是的话,会自动用系统默认编码帮第二个操作符decode
reload(sys)
sys.setdefaultencoding('utf8')
print type('大学') # str
print type(s[-2:]) # unicode
print s[-2:] == '大学' # 返回True # python在用==比较时,如果第一个操作符是unicode而第二个不是的话,会自动用系统默认编码帮第二个操作符decode
print '大学'.decode('utf8')
- 总结
python在用==比较时,如果第一个操作符是unicode而第二个不是的话,会自动用系统默认编码帮第二个操作符decode。
reload是用于重新加载之前import的模块。这里需要重新加载sys的原因是:python在加载模块时候删除了sys中的setdefaultencoding方法(可能是出于安全起见),所以需要reload这个sys模块。
python中内置的默认open在读取文件的时候以字节串str的形式,读出一个个字节。读取后要用正确的编码才能decode成正确的unicode,所以要知道原来在文件中的编码。
写文件的时候也是一个道理,用str类型,以字节的形式写入,这个str是以某种编码方式编码的,要注意用正确的编码方式编码,一般是按utf8编码后写文件。
如果你用unicode类型写入,python会根据系统默认编码来把unicode编码成str再写入文件。因为写入文件需要的是str,是str就写,不是我就把你转成str再写。
简单原则,尽量用str写入,避免使用默认编码,这样也不用在开头修改默认编码。