之前的代码片段都是在python解析器的交互界面进行的。为了能让python代码重复使用,需要把代码保存到一个文件中。以后就可以继续使用这些代码了。
9.1代码文件的保存和运行
代码文件的保存很简单,就是直接把之前敲过的代码一行行放到文件里面保存就可以了。下面的例子把一个print语句保存为hello.py。
print('hello '+str(2018))
这时在命令行中键入
python hello.py
就可以看到运行结果。
hello 2018
代码文件也可以直接通过双击或者命令行的方式运行。
在windows系统里面,把python代码文件保存为'.py'后缀的文件,双击文件就可以运行。
在linux系统里面,在python文件的第一行加入一句
#! /usr/bin/env python
注意,这里'#!'一定要是文件第一行开头的两个字符,并且这一行最好使用'\n'换行,而不是windows系统里面的'\r\n'。所以linux下面运行的代码文件最好在linux编辑器中编辑,在windows编辑器中编辑的代码到了linux下面可能会出现格式问题。
然后使用chmod把代码文件设置成可执行文件
chmod 777 hello.py
这样就可以直接在命令行运行。
./hello.py
9.2代码的字符串编码
代码保存到文件中也可能会引发乱码的问题。因为代码文件中经常会有中文的定义。比如说下面的语句就定义了一个中文,而且还没有使用u操作把它转化为unicode。
s='中'
它的编码到底是gbk还是utf8,还是别的编码,取决于这个代码文件是用什么编码来保存的。
要做到自动识别一个文件到底是什么编码,实际上也不难,但是会非常麻烦。放眼全球,韩文日文阿拉伯文法文德语等等各种编码不下百种,挨个尝试解析一下将会是非常耗时的事情。所以这件事python是不会去做的。
因此每个代码文件中如果含有非ascii编码的话,都需要在代码文件中声明这个代码文件是用什么编码保存的,这样python的解析器好知道代码中定义的非ascii字符的真正编码。
这个声明需要在代码文件的第一行或者第二行的位置使用。一般情况下会使用
# coding=utf-8
或者
# -*- coding: utf-8 -*-
来进行声明
如果第一行已经被
#!/usr/bin/env python
占用了,那么就在第二行做编码声明;如果没有,那么就在第一行做编码声明。
编码声明其实不会很严格,只要符合正则表达式
^[ \t\v]*#.*?coding[:=][\t]*([-_.a-zA-Z0-9]+)
的就可以。(正则表达式后面再讲)可以看到,有coding这个单词,有=号或者是:号,基本就会被认为是编码声明了。在写法上还是很自由的,不过还是建议少点个性化,使用最简单的就可以了。
# coding=utf-8
如果没有这个声明的话,会有什么样的效果。我们把下面这两句代码存储到文件testencode.py中,并且使用gb18030编码进行存储。
s='中'
print(repr(s))
运行的时候很快就发现了错误。
$ python testencode.py
File "testencode.py", line 1
SyntaxError: Non-ASCIIcharacter '\xd6' in file testencode.py on line 1, but no encoding declared; seehttp://python.org/dev/peps/pep-0263/ for details
解析器发现了非ascii编码的字符而且不知道从何解析。
撞了南墙后,再回头在第一行加入声明语句。修改代码为
# coding=gb18030
s='中'
print(repr(s))
此时再运行看看,代码就可以正常运行了。打印的内容是s字符串的gb18030的字符编码。
$ python testencode.py
'\xd6\xd0'
之前讲过,要把其它编码的中文字符串先使用decode转为unicode,然后再把unicode使用encode转为其它的编码,这个是最符合规矩的流程。但是偏偏有一些猴急的人,想要跳过unicode这个中介。希望直接就能从gb18030到utf8。或者从utf8直接到gb18030。或者直接就不希望在代码中出现unicode这个碍眼货。于是python只好满足了这些人的愿望,在编译器的设置中提供默认编码的设置方法。这样python的编译器就可以默默把非ascii字符按照默认编码转成unicode。unicode不是真的不见了,而是被python藏起来了而已。
这个默认编码的设置方法,就是sys模块里面的setdefaultencoding()方法。
在使用的时候,需要在代码中加三句。
import sys
reload(sys)
sys.setdefaultencoding('gb18030')
好多人都问,之前不是import了sys,为什么又要reload一次sys呢?python的语句挺简洁的,但是后面的编译机制却盘根错节,一点都不优美。这里是因为编译器在做初始化过程中,会在执行完所有的import语句后,自动加载一个叫做site模块的东西,主要用来初始化运行路径之类的,它起来了之后,setdefaultencoding方法就从sys命名空间中被删除了。这真是一件神奇的事情,其它的语言里面这种事情是闻所未闻。只怪python太灵活,所有的东西都是对象,所有对象都有命名空间,所有命名空间都可以随便修改。所以这个时候如果不reload的话,会提示sys里面没有setdefaultencoding这个方法的。
好吧,再回到刚才的问题,加入了设置默认编码的设置后,修改代码为
# coding=gb18030
import sys
reload(sys)
sys.setdefaultencoding('gb18030')
s='中'
print(type(s))
print(repr(s))
sutf8=s.encode('utf8')
print(repr(sutf8))
上面的代码并没有使用decode把s字符串转化为unicode,而是直接使用encode转化为utf8 。
再运行一下
$ python testencode.py
'\xd6\xd0'
'\xe4\xb8\xad'
可以看到,使用了默认编码之后,在代码中已经可以直接处理gb18030编码了。不需要decode成unicode了。
如果代码里面不是只处理某一种字符编码的话,不建议自行设置默认编码。上面的代码设置了gb18030为默认编码,如果碰到了utf8编码的字符串,其实还是需要乖乖decode成unicode进行处理的。
领取专属 10元无门槛券
私享最新 技术干货