好记性不如烂笔头,看到Python Command-Line Options中有关字节码的生成,记录起来。
Python的字节码文件有2种,文件后缀名分别是.pyc和.pyo,前者是普通的字节码, 后者是经过优化的字节码(速度稍快点,但可能加载稍慢点)。
先说什么是字节码文件(bytecode)?
会写Java Hello World的一定知道什么是bytecode了,简单的说它就是一个从source code编译而来的中间文件(用于不同操作系统平台的解释器执行)。 比如,J说日语,C说中文,沟通起来不畅通,请一个翻译,把J和C的语言都翻译成英语,这个英语就可以理解成bytecode,一种中间语言。
bytecode的好处就是加载快,而且可以跨平台,同样一份bytecode,只要有操作系统平台上有相应的Python解释器,就可以执行(而不需要source code)。不同版本的Python编译的bytecode是不兼容的,Python 2.6编译的bytecode拿到Python 2.7上去执行就不行了。
什么时候会生成bytecode?
Python解释器一般会自动把.py文件转换成bytecode,然后再执行它。当你第一次把.py文件当作module导入,或者对应的.py文件比.pyc文件的修改时间还要新时,Python解释器都会再从source code生成相应的新bytecode。这样当你下次再次运行程序时,就会直接从bytecode运行,从而节省便宜时间。
这里需要注意,有些情况bytecode并不会生成。遇到目录写权限的问题时。(比如你编写代码和运行代码使用的具有不同权限的用户角色,Linux上很常见)
运行一个script并不会被当成是import操作,所以可能也不会生成bytecode。(比如:你有个一个a.py的文件,其中在a.py里,你import了b.py,那么运行python a.py后,会生成b.pyc,而不会生成a.pyc)
怎么手动生成bytecode呢?
有时候需要手动的生成bytecode,可以利用下面几种方法:
1. 利用py_compile模块import py_compile
py_compile.compile('a.py')
2. 利用compileall模块import compileall
compileall.compile_file('a.py')
# compileall.compile_dir('.', maxlevels=0) 编译当前目录所有.py文件,需要指定maxlevels=0,否则默认要扫描10层子目录
3. 利用python命令行python -m py_compile a.py # 或 python -m py_compile *.py
python -m compileall a.py # 或 python -m compileall *.py
python -O -m py_compile a.py # 如果跟上 -O 选项以后,会生成 a.pyo
python -O -m compileall a.py # 同上
如果漏掉了compileall的参数(比如:python -m compileall),那么会将sys.path中source code生成相应的bytecode
有趣的Python命令行,直接执行代码:python -c "import sys
print 'hello command line'
for i in range(2):
print i, len(sys.argv)
"
再看一个有趣的Python命令行(sys.argv[0]是-c,sys.argv[1:]分别是 x y z 123)python -c "import sys
for i in sys.argv:
print i
" x y z 123
That's it!