好冷的Python–源文件编码

原文链接:http://www.juzicode.com/archives/741

我们在看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和它的备胎们

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注