1. python2的默认编码是ascii,python3的默认编码是utf-8

Python 2.7.12 (v2.7.12:d33e0cf91556, Jun 27 2016, 15:24:40) [MSC v.1500 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getdefaultencoding()
'ascii'


Python 3.6.2 (v3.6.2:5fd33b5, Jul  8 2017, 04:57:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> sys.getdefaultencoding()
'utf-8'

2. 常见编码情况

print sys.getdefaultencoding()    #系统默认编码
print sys.getfilesystemencoding() #文件系统编码
print locale.getdefaultlocale()   #系统当前编码
print sys.stdin.encoding          #终端输入编码
print sys.stdout.encoding         #终端输出编码

window终端输出

ascii
mbcs
('zh_CN', 'cp936')
cp936
cp93

linux终端输出

ascii
UTF-8
('zh_CN', 'UTF-8')
UTF-8
UTF-8

3. python str->unicode是decode,unicode->str是encode,见下图

python更改默认编码格式为gbk python的默认编码_python更改默认编码格式为gbk

>>> import sys
>>> sys.getdefaultencoding()
'ascii'
>>> a='强'  # str字符串
>>> b=u'强'  # unicode字符串
>>> print isinstance(a, str)
True
>>> print isinstance(b, unicode)
True

# 因为只有unicode才有encode方法,此处python会做默认转换,也即a.decode('ascii').encode('utf-8')
# 会获取默认编码ascii转换中文字符,当然错误,报UnicodeDecodeError
>>> a.encode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 0: ordinal not in range(128)

# 指定utf-8再转换就会正确解析,结果unicode字符串,注意u'\u01ff'前面的u,观察这个即可知道当前是unicode or 二进制字节码
>>> a.decode('utf-8')
u'\u01ff'

# 不需转换,显示二进制字节码
>>> str(a)
'\xc7\xbf'

# b是unicode类型,需转化为str类型,b.encode('ascii')报错
>>> str(b)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'ascii' codec can't encode character u'\u5f3a' in position 0: ordinal not in range(128)

# unicode没有decode,需转为str,b.encode('ascii'),转化时出错
>>> b.decode('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "C:\Python27\lib\encodings\utf_8.py", line 16, in decode
    return codecs.utf_8_decode(input, errors, True)
UnicodeEncodeError: 'ascii' codec can't encode character u'\u5f3a' in position 0: ordinal not in range(128)

# 指定编码正确转换
>>> b.encode('utf-8')
'\xe5\xbc\xba'
>>>

 

4. python进行同时包含str和unicode的运算时(+,%等),一律转为unicode处理,当然结果也是unicode

>>> a='强'  # str字符串
>>> b=u'强'  # unicode字符串
# 这里str和unicode运算,全部转化为unicode,str转unicode时用ascii转换,当然报错
>>> a+b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 0: ordinal not in range(128)

# 此处都是str不用转,正确
>>> '强%s' % a
'\xc7\xbf\xc7\xbf'

# 此处b是unicode,相当于'强%s'.decode('ascii') % b, 所以错误
>>> '强%s' % b
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 0: ordinal not in range(128)

# 反过来也是一样的
>>> u'强%s' % a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
UnicodeDecodeError: 'ascii' codec can't decode byte 0xc7 in position 0: ordinal not in range(128)
>>> u'强%s' % b
u'\u5f3a\u5f3a'

5. 以上都是默认ascii编码导致的,那么设置下python默认编码就可以了

>>> import sys
>>> sys.setdefaultencoding('utf-8')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'setdefaultencoding'
# 注意需要reload下
>>> reload(sys)
<module 'sys' (built-in)>
>>> sys.setdefaultencoding('utf-8')
>>> sys.getdefaultencoding()
'utf-8'

>>> a='强'  # str字符串
>>> b=u'强'  # unicode字符串
# 再进行以上操作,都正确了
>>> a+b
u'\u01ff\u5f3a'
>>> '强%s' % a
'\xc7\xbf\xc7\xbf'
>>> '强%s' % b
u'\u01ff\u5f3a'
>>> u'强%s' % a
u'\u5f3a\u01ff'
>>> u'强%s' % b
u'\u5f3a\u5f3a'
>>> a.encode('utf-8')
'\xc7\xbf'
>>> b.decode('utf-8')
u'\u5f3a'
>>> str(a)
'\xc7\xbf'
>>> str(b)
'\xe5\xbc\xba'

6. python文件默认编码也是ascii,假如有中文就会报错如下

假如有t.py文件,里面有非ascii字符

# file t.py

a='夏天'

执行时会报错

E:/>python t.py
  File "t.py", line 1
SyntaxError: Non-ASCII character '\xcf' in file t.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details

 在头部加入,指定源代码编码格式

# -*- coding: utf-8 -*-
或者
#coding=utf-8

声明下默认编码即可

7. 如文件编码为ANSI的,里面有中文的unicode定义,也会报错

t.py

#coding=utf-8
a='夏天'
b=u'秋天'

执行也会报错 

E:\>python t.py
  File "t.py", line 3
    b=u'秋天'
SyntaxError: (unicode error) 'utf8' codec can't decode byte 0xc7 in position 0: invalid continuation byte

把文件编码改为UTF-8即可解决

8. print, 终端乱码

print和终端相关,会根据sys.stdin.encoding,  sys.stdout.encoding来处理,如果输出的字符串和终端编码不一样就会乱码

t.py

#! -*- coding:utf-8 -*-
a='中文'
print a
print type(a)

windows下 

E:\>python t.py
涓枃
<type 'str'>

linux下

# python t.py 
中文
<type 'str'>

因为windos控制台编码为cp936编码即gbk编码,而变量a本身编码为utf-8

那么定义的unicode字符如何呢,见下面

#! -*- coding:utf-8 -*-
a='中文'
print a  # 涓枃
print type(a)  # <type 'str'>
b=a.decode('utf-8')  
print b  # 中文

b=u'中文'
print b  # 中文
print type(b)  # <type 'unicode'>
print b.encode('gbk')  # 中文

str(b)  # UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

可见,unicode的字符print正常,按gbk encode->str时也正常,为什么呢

可这样简单理解,print输出到终端时,要是str,如果str的编码与终端编码不一致,那么乱码

如果不是str,则需要转为str,这个是获取终端编码,也即python替你做了, encode('gbk')

但str(b)咋又报错了呢,这是因为,str是python内建函数,会获取getdefaultencoding,而这个编码是ascii,所以报错

再进一步,加入重定向到文件呢

#! -*- coding:utf-8 -*-
b=u'中文'
print b

python t.py > result 

会报错UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

因为输出到控制台时,print 使用的是控制台的默认编码,而重定向到文件时,print 就不知道使用什么编码了,于是就使用了默认编码 ascii 导致出现编码错误。这时我们就不应该让python帮我们做,我们自己指定

#! -*- coding:utf-8 -*-
b=u'中文'
print b.encode('utf-8')

这样就会正常

9. write

#! -*- coding:utf-8 -*-
with open('ttt.txt', 'w') as f:
  f.write('test') # 正常写入
  f.write('夏天') # 正常写入
  #f.write(u'秋天') # 错误,由于是unicode,python要转换为str再写入,encode时用的ascii,触发UnicodeEncodeError异常
  f.write(u'秋天'.encode('utf-8')) # 写入正常,unicode->str

或者指定默认编码,这样就不用手动encode了,见下

#! -*- coding:utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
with open('ttt.txt', 'w') as f:
  f.write('test,') # 正常写入
  f.write('夏天,') # 正常写入
  f.write(u'秋天,') # 写入正常

10. read

#! -*- coding:utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
with open('ttt.txt', 'w') as f:
  f.write('test,') # 正常写入
  f.write('夏天,') # 正常写入,乱码
  f.write(u'秋天,') # 写入错误,由于是unicode,python要转换为str再写入,encode时用的ascii,触发UnicodeEncodeError异常
  #f.write(u'秋天'.encode('utf-8')) # 写入正常,unicode->str

with open('ttt.txt') as f:
  for line in f:
    print line, type(line)  # test澶忓ぉ绉嬪ぉ <type 'str'>
    line2 = line.decode('utf-8')
    print line2, type(line2) # test夏天秋天 <type 'str'>

print '-----------------------------'

# 通过io包下的open打开文件可设置编码
from io import open
with open('ttt.txt', encoding='utf-8') as f:
  for line in f:
    print line, type(line) # test夏天秋天 <type 'unicode'>

# 由上可见,内建函数open,不能指定编码,其按客户端所在编码解码,line类型是str
# io.open可指定编码,同时line读取类型为unicode

建议措施:

以上所有其实就是在不同地方python默认转换时采用的编码和我们设置的编码不一致导致的,所以分析时先分析当前python应该获取什么编码,然后再分析。比如,str(..) 会获取getdefaultencoding,print会获取sys.stdout.encoding等

1. 牵扯到中文的地方,都声明头部编码,同时文件编码设为utf-8

# -*- coding: utf-8 -*-
或者
#coding=utf-8

2. 同时设置sys 默认编码

import sys
reload(sys)
sys.setdefaultencoding('utf-8')

3. python代码内部请全部使用unicode编码,在获取外部内容时,先decode为unicode,向外输出时再encode为str

4. 在定义变量或者正则时,也定义unicode字符,如a=u”中文”;res=r””+u”正则”。