<code>*.py</code>:源码文件,由 Python 程序解释。
<code>*.pyc</code>:源码经编译后生成的二进制字节码(Bytecode)文件。
<code>*.pyo</code>:优化编译后的程序,也是二进制字节码文件。
虚拟机怎么执行py脚本:
完成模块的加载和链接;
将源代码翻译为PyCodeObject对象(这就是字节码),并将其写入内存当中(方便CPU读取,起到加速程序运行的作用);
从上述内存空间中读取指令并执行;
程序结束后,根据命令行调用情况(即运行程序的方式)决定是否将PyCodeObject写回硬盘当中(也就是直接复制到.pyc或.pyo文件中);
之后若再次执行该脚本,则先检查本地是否有上述字节码文件。有则执行,否则重复上述步骤。
Python 在解释源程序时分为两步:
第一步:将<code>源码</code>转为<code>字节码</code>
第二步:将<code>字节码</code>转换为<code>机器码</code>
pyc 文件是由 Python 解释器将 模块的源码 转换为 字节码,下次运行程序的时候,就可以跳过 从源码到字节码 的过程,直接加载 pyc 文件。
<code>(pyc,py代表pychon,c 是 compiled的含义,pyc即编译过的python文件 )</code>
1.1命令方式---生成pyc文件:
或者
<code>把单个.py文件编译为字节码文件</code>
1.2 脚本方式---生成pyc文件:
其下的py_compile.compile(file[, cfile[, dfile[, doraise]]])可将.py文件编译生成.pyc文件(默认),对应的参数解释如下
file,表示需要生成.pyc或.pyo文件的源脚本名(字符串);
cfile,表示需要生成.pyc或.pyo文件的目标脚本名。此外,当且仅当所使用的解释器允许编译成.pyo文件,才能以“.pyo”结尾。这也就是为什么会在函数功能解释上加上“(默认)”这两个字的原因。
dfile,表示编译出错时,将报错信息中的名字“file”替换为“dfile”。
doraise,设置是否忽略异常。若为True,则抛出PyCompileError异常;否则直接将错误信息写入sys.stderr(什么!不知道sys.stderr?!温馨提示:sys.stderr是Python自带的标准错误输出)
1 命令方式---生成pyc文件:
或者
2 脚本方式---生成pyc文件
1 命令方式---生成pyo文件:
或者
note:
-m参数相当于import,-m py_compile 相当于import py_compile,也即把后边跟随的库模块当做脚本运行。这样生成的字节码文件后缀名为.pyc文件。
-O参数表明要生成更加紧凑的优化后的字节码, 这样生成的字节码文件后缀名为.pyo文件。
-OO会进一步移除-O选项生成的优化后的字节码文件中的文档字符串,生成的文件后缀名仍然为.pyo文件。
pyo文件也是优化编译后的程序(相比于.pyc文件更小),也可以提高加载速度。但对于嵌入式系统,它可将所需模块编译成.pyo文件以减少容量
注意不同版本编译后的pyc文件是不同的,比如3.4编译的pyc文件在3.3版本的python是无法执行的。
当我们的python文件被编译过,文件之间存在import关系,就会生成一个<code>__pyc__</code>文件夹。
若你在命令行直接输入“python path/to/projectDir”(假设projectDir目录含有“__main__.py”文件,以及其他将要调用的模块),那么程序运行结束后便自动为当前目录下所有的脚本生成字节码文件,并保存于本地新文件夹__pycache__当中
或者是,在命令行输入“python path/to/projectDir/__main__.py”,则生成除__main__.py外脚本的字节码文件。不过总的来说,上述这两种行为都大大缩短了项目运行前的准备时间。
模块在每次导入前总会检查其字节码文件的修改时间是否与自身的一致。若是则直接从该字节码文件读取内容,否则源模块重新导入,并在最后生成同名文件覆盖当前已有的字节码,从而完成内容的更新(详见import.py)。这样,就避免了修改源代码后与本地字节码文件产生冲突。
大多数人都以为是才智成就了科学家,他们错了,是品格。---爱因斯坦