原文链接:http://www.juzicode.com/python-cold-source-file-encode/
我们在看Python源码的时候,经常看到py文件的前面2行出现这样的内容:
#!/usr/bin/python
# -*- coding: UTF-8 -*-
第2行的 ”-*- coding: UTF-8 -*-” 的作用是告诉Python解释器这个源码文件所采用的编码方式是UTF-8。本着猎奇的心理,我们来看下用其他的编码方式保存源码文件试试。 在notepad++的格式选项下可以选择保存文件的格式,“以UTF-8无BOM格式编码”就是指UTF-8编码格式 。
我们试着用“以ANSI格式编码”保存文件,同时命名为coding-gbk.py,并在文件中输入有中文字符串内容,但是在第2行的内容中仍然声明为UTF-8的编码格式,试着运行这个py文件,果然抛异常了,提示utf-8格式在解析某个字节的时候失败了。
我们将第2行内容中coding: 后面的UTF-8修改为gbk,一切ok,运行正常:
#!/usr/bin/python
# -*- coding: gbk -*- 这里修改为gbk
print('公众号:')
print('桔子code')
===========结果:
公众号:
桔子code
从这个例子可以看出,文件的实际编码方式(选择保存的编码格式)应该要和声明的编码方式(源文件中第2行的声明)保持一致!这个地方敲黑板!
另外通过实验也可以看到如果没有在代码中声明编码方式,解释器是默认按照utf-8格式去解析的,所以在没有第2行声明的时候保存文件的编码格式应该选择utf-8格式。
行文到此如果就结束的话,这些个内容就不那么高冷了,继续,继续!下面实验的都是用 “以ANSI格式编码”保存源码文件。
干掉第1行
我们来看下这两行注释内容,第一行的”!/usr/bin/python”用在linux系统里直接运行py文件时,告诉shell这个文件的运行是要调用python解释器,所以在windows系统下,第1行的内容是没有任何实际意义的,所以把第一行去掉,看看效果:
# -*- coding: gbk -*-
print('公众号:')
print('桔子code')
# notepad++"以ANSI格式编码"保存文件
===========结果:
公众号:
桔子code
All is best! 从这里可以看到编码方式的声明在第1行或者第2行都是有效的!那在第一行随便写点什么内容会是什么结果呢?
# are you kiding me
# -*- coding: gbk -*-
print('公众号:')
print('桔子code')
# notepad++"以ANSI格式编码"保存文件
===========结果:
公众号:
桔子code
没什么问题!一切OK!
第一行来一段中文试试:
# 你是凯丁吗
# -*- coding: gbk -*-
print('公众号:')
print('桔子code')
# notepad++"以ANSI格式编码"保存文件
============结果:
File "coding-gbk-1st-chinese.py", line 1
SyntaxError: Non-UTF-8 code starting with '\xc4' in file coding-gbk-1st-chinese.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details
好了现在不香了,如果第一行用了中文,Python解释器也不去识别第2行的内容了,虽然第2行告诉解释器这里用的是gbk编码,注意这个文件要用 “以ANSI格式编码”保存文件哦,不然实验就没什么意义了。
还能再精简么?
看到这行内容”-*- coding: gbk -*-”,coding: gbk两端的东西太多了,看起来好像有点难受,再精简下,把这些什么多余的 *- 符号都干掉:
#coding: gbk
print('公众号:')
print('桔子code')
# notepad++"以ANSI格式编码"保存文件
============结果:
公众号:
桔子code
不错,现在这个样子舒服多了,原来那些乱七八糟的东西都是可以裁剪的,最简单一句“coding: gbk”就行了。
冒号换等号
冒号换成等号试试,居然也能通过:
#coding=cp936
print('公众号:')
print('桔子code')
# notepad++"以ANSI格式编码"保存文件
============结果:
公众号:
桔子code
能用encoding:gbk么
在用open()函数创建文件对象的时候,用到的编码方式入参名称是encoding:
with open('example-a3.txt','a+',encoding='utf8') as fileobj:
pass
这里我们也换成encoding试试?
#encoding: gbk
print('公众号:')
print('桔子code')
# notepad++"以ANSI格式编码"保存文件
============结果:
公众号:
桔子code
也是没有问题的!
用decoding:gbk试试?
纯属无聊,试下decoding:
#decoding: gbk
print('公众号:')
print('桔子code')
# notepad++"以ANSI格式编码"保存文件
============结果:
公众号:
桔子code
什么,又通过了!不会是哪里搞错了吧,赶紧把gbk换成gxxbxxk试下,幸好是不通过的,看来decoding也是可以的。
到底是怎么回事
对比decoding、encoding和coding的差别,可以看出来解释器在遇到这行内容的时候应该是只要找到coding这几个字符就可以了,其他多余的内容都过滤掉了。大胆猜测,小心求证, coding前后换成别的字符试试:
#are you kiding me? coding:gbk no,i am serious
print('公众号:')
print('桔子code')
# notepad++"以ANSI格式编码"保存文件,gbk和no之间有空格
============结果:
公众号:
桔子code
#are you kiding me? coding:gbkno,i am serious
print('公众号:')
print('桔子code')
# notepad++"以ANSI格式编码"保存文件,gbk和no之间木有空格
============结果:
File "coding-gbk-simple-random2.py", line 1
SyntaxError: encoding problem: gbkno
#你是凯丁吗?coding:gbk不,我是希尔瑞斯
print('公众号:')
print('桔子code')
# notepad++"以ANSI格式编码"保存文件,gbk和不之间没有空格
============结果:
公众号:
桔子code
果然,和猜测是一致的。coding:gbk前面可以有任意字符,后面如果是英文必须有空格,中文可以无空格。
做了这么多试验,可以先总结下了:
1.声明编码方式必须和文件实际采用的编码方式一致;
2.声明编码方式的语句可以在第1行或者在第2行;
3.如果声明编码方式的语句在第2行, 第1行中不能有中文;
4.coding=xxx 的前面可以有任何字符,xxx后面如果是英文必须先有一个空格,如果是中文没有要求;
5.coding=xxx和coding:xxx效果一样;
在前面的第1行换成中文的时候有这么一段错误提示:SyntaxError: Non-UTF-8 code starting with ‘\xc4’ in file coding-gbk-1st-chinese.py on line 1, but no encoding declared; see http://python.org/dev/peps/pep-0263/ for details。打开这个pep链接看看有些什么内容,结果发现下面这句话:
“更准确地说,第一或者第二行内容要满足下面这个正则表达式”。 散了!散了!玩了这么久还不如人家一句话来得精简!
推荐阅读:
好冷的Python–tuple和逗号的恩怨情仇
好冷的Python–三引号注释,你的要求为什么这么多!
好冷的Python–源文件编码
好冷的Python–pass和它的备胎们