17.12. compileall — 将源码编译为字节码
目的:将源代码文件转换为字节编译的版本。
这个 compileall
模块可以将 Python 源代码文件找出来并将他们编译为字节码,之后将结果保存成 .pyc
文件。
编译一个文件夹
这个 compile_dir()
方法用于递归式地扫描一个文件夹并对其中的文件进行字节编译。
compileall_compile_dir.py
import compileall
import glob
def show(title):
print(title)
for filename in glob.glob('examples/**',
recursive=True):
print(' {}'.format(filename))
print()
show('Before')
compileall.compile_dir('examples')
show('\nAfter')
默认情况下,所有的子文件夹的扫描深度都是 10。输出文件被写入到一个叫做 __pycache__
的文件夹并基于 Python 编译器的版本来命名。
$ python3 compileall_compile_dir.py
Before
examples/
examples/README
examples/a.py
examples/subdir
examples/subdir/b.py
Listing 'examples'...
Compiling 'examples/a.py'...
Listing 'examples/subdir'...
Compiling 'examples/subdir/b.py'...
After
examples/
examples/README
examples/a.py
examples/subdir
examples/subdir/__pycache__
examples/subdir/__pycache__/b.cpython-36.pyc
examples/subdir/b.py
examples/__pycache__
examples/__pycache__/a.cpython-36.pyc
忽略不参与编译的文件
若要过滤文件夹,可以使用 rx
参数来提供一个正则表达式用于匹配你想要排除的文件夹的名称。
compileall_exclude_dirs.py
import compileall
import re
compileall.compile_dir(
'examples',
rx=re.compile(r'/subdir'),
)
该版代码可以将名为 subdir
的子文件夹中的文件排除掉。
$ python3 compileall_exclude_dirs.py
Listing 'examples'...
Compiling 'examples/a.py'...
Listing 'examples/subdir'...
其中, maxlevels
参数用于控制递归的深度。比如,想完全避免递归,可以给该参数传入 0
。
compileall_recursion_depth.py
import compileall
import re
compileall.compile_dir(
'examples',
maxlevels=0,
)
只有传给了 compile_dir()
方法的文件夹中的文件才会被编译。
$ python3 compileall_recursion_depth.py
Listing 'examples'...
Compiling 'examples/a.py'...
编译 sys.path
所有在 sys.path 路径下找到的 Python 源代码文件都可以通过对 compile_path()
方法的一次简单调用来进行编译。
compileall_path.py
import compileall
import sys
sys.path[:] = ['examples', 'notthere']
print('sys.path =', sys.path)
compileall.compile_path()
这个例子将 sys.path
的默认内容替换掉用于避免运行脚本时的许可错误,但仍然可以展现出该方法的默认行为。注意, maxlevels
的值默认设为了 0
。
$ python3 compileall_path.py
sys.path = ['examples', 'notthere']
Listing 'examples'...
Compiling 'examples/a.py'...
Listing 'notthere'...
Can't list 'notthere'
编译独立文件
若要编译单个文件,而不是一整个文件夹的文件,可使用 compile_file()
方法。
compileall_compile_file.py
import compileall
import glob
def show(title):
print(title)
for filename in glob.glob('examples/**',
recursive=True):
print(' {}'.format(filename))
print()
show('Before')
compileall.compile_file('examples/a.py')
show('\nAfter')
第一个参数可以是文件名,完整路径或相对路径。
$ python3 compileall_compile_file.py
Before
examples/
examples/README
examples/a.py
examples/subdir
examples/subdir/b.py
Compiling 'examples/a.py'...
After
examples/
examples/README
examples/a.py
examples/subdir
examples/subdir/b.py
examples/__pycache__
examples/__pycache__/a.cpython-36.pyc
在命令行中执行编译
在命令行中调用 compileall
也是可以的,所以这个模块可以通过 Makefile 来集成到构建系统中。比如:
$ python3 -m compileall -h
usage: compileall.py [-h] [-l] [-r RECURSION] [-f] [-q] [-b] [-d
DESTDIR]
[-x REGEXP] [-i FILE] [-j WORKERS]
[FILE|DIR [FILE|DIR ...]]
Utilities to support installing Python libraries.
positional arguments:
FILE|DIR zero or more file and directory names to
compile; if
no arguments given, defaults to the
equivalent of -l
sys.path
optional arguments:
-h, --help show this help message and exit
-l don't recurse into subdirectories
-r RECURSION control the maximum recursion level. if
`-l` and `-r`
options are specified, then `-r` takes
precedence.
-f force rebuild even if timestamps are up
to date
-q output only error messages; -qq will
suppress the
error messages as well.
-b use legacy (pre-PEP3147) compiled file
locations
-d DESTDIR directory to prepend to file paths for
use in compile-
time tracebacks and in runtime
tracebacks in cases
where the source file is unavailable
-x REGEXP skip files matching the regular
expression; the regexp
is searched for in the full path of each
file
considered for compilation
-i FILE add all the files and directories listed
in FILE to
the list considered for compilation; if
"-", names are
read from stdin
-j WORKERS, --workers WORKERS
Run compileall concurrently
重新创建下先前的例子,忽略掉 subdir
文件夹,运行:
$ python3 -m compileall -x '/subdir' examples
Listing 'examples'...
Compiling 'examples/a.py'...
Listing 'examples/subdir'...
供参考
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。