本文对一个Python单文件脚本的基本要素,做一个简单介绍。
Hello world
先简单展示一个hello.py
脚本:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
""" A hello world script. """
from __future__ import print_function
import sys
def main():
""" The entry function of this script. """
print('Hello world!')
print(sys.platform)
return 0
if __name__ == '__main__':
raise SystemExit(main())
执行与输出:
$ python hello.py
Hello world!
darwin
下面以这个脚本为例,从上到下,依次介绍Python脚本的基本要素。
脚本开头的#!
一般Python脚本开头,都会有一行#!
。例如:
#!/usr/bin/env python
这被称为Shebang,是类Unix系统的一种机制,指明该文本文件应该使用什么方式来执行。
在使用python hello.py
来执行时,这行没有什么用。在给文件添加可执行权限,用./hello.py
这种形式来执行时,就需要这个机制了。Windows系统通常使用后缀名来当做文件类型的指定,而类Unix系统则需要这个机制。
如果不指定,则默认使用当前的shell。
对Bash来说,通常使用#!/bin/bash
。因为,系统的bash一般都是放那里,直接指定绝对路径,通常不会有问题。而对Python来说,位置就不那么确定了。所以,通常使用env python
的形式,只要python
有在可执行路径就行。
最后,这行在Windows,或只会被import的py文件中,不需要写。
Shebang后面的一行注释
除了这个:
# -*- coding:utf-8 -*-
其实还有另一种常见的形式:
# coding=utf-8
当然,对Vimer来说,这种也是可以的:
# vim: set fileencoding=utf-8 :
Vim打开该Python文件时,会自动执行set fileencoding=utf-8
。这是Vim编辑器的一个特性。
这是什么东西,为什么会生效呢?
原因在PEP-0263。
The encoding information is then used by the Python parser to interpret the file using the given encoding. Most notably this enhances the interpretation of Unicode literals in the source code and makes it possible to write Unicode literals using e.g. UTF-8 directly in an Unicode aware editor.
在第一或第二行,只要满足以下正则表达式的形式,都是合法的编码指定。
^[ \t\v]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)
这既是Python的注释,又是Python解释器可以接受的编码参数,还可以被编辑器读作自身的设定。而不同编辑器可以接受的形式不同,所以就成了这么个样子。
如果不指定,则默认编码为ASCII。
Python will default to ASCII as standard encoding if no other encoding hints are given.
pydoc
以下这种,用三个双引号"""
包含,出现在文档、类、函数、方法开头的字符串,就是pydoc。
""" A hello world script. """
pydoc
是Python安装后就自带的一个文档工具,可以在命令行查看Python的文档。比如,我们可以查看刚写的hello.py
的文档。
pydoc hello
Help on module hello:
NAME
hello - A hello world script.FILE
/home/user/Playground/Python/hello/hello.pyFUNCTIONS
main()
The entry function of this script.DATA
print_function = _Feature((2, 6, 0, 'alpha', 2), (3, 0, 0, 'alpha', 0)...
除此之外,pydoc还可以像javadoc那样,生成网页文档。
import其它包
from __future__ import print_function
import sys
除了一些少量的关键字、内置函数与字段以外,要使用其它模块的东西,都需要显式导入。
这里,从__future__
导入了Python3的print
函数,来替换Python2的print关键字,是一种2、3兼容的打印方式。而sys
模块,则提供了一些系统信息,这里是用来打印copyright。
执行入口
除了import其它包,任何一个Python脚本都可以被其它脚本import。比如,在同目录下的另一个脚本,就可以import hello
,使用这个文件中的函数。
import hello
hello.main()
为了使hello.py
在被导入时,不会自动执行main函数中的内容,而在被执行时,可以自动执行main函数,通常使用以下方式来区分。
if __name__ == '__main__':
main()
被执行时,这个if
就会成真;而被导入时,__name__
的值是模块名(单文件的情况就等于文件名)hello
,main函数不会被执行。
与C语言不同,Python的执行入口并非main函数,而是和Bash类似,是从上到下完整执行一遍。这里用main作为唯一函数的名称,作为功能的总入口,只是一种可有可无的习惯。
执行出口
正常情况下,脚本执行完最后一行,就自动退出了。而如果要控制脚本的退出位置,比如在执行到一半时退出,就需要用到以下形式。
raise SystemExit(main())
SystemExit
是Python内置异常的一种,专门用来退出程序。实际上,任何一种没有被except的异常,都会导致程序异常退出。SystemExit
的特殊在于,可以控制返回值。
任何一个CLI程序,都需要在退出时,返回一个int值给系统或其它调用方。如果是0,则表示正常退出;如果是其它值,则表示错误码。
SystemExit()
如果被传入0、None、或者无参数,则返回0;如果是其它整数值,则返回该数值;如果是其它对象,则打印该对象到stderr,并且返回1。
这一句还有一个常用的等效形式:
sys.exit(main())
这个形式比较易读,不过需要import sys
。
返回值,即错误码。为0则表示无错,正常执行结束;其它值则表示各种错误。要完整摸清这个概念的来龙去脉,需要对Linux、C语言的main函数、Bash的if判断,都有一点了解。