pyc是一种二进制文件,是由py文件经过编译后,生成的文件,是一种byte code字节码,py文件变成pyc文件后,加载的速度有所提高,而且pyc是一种跨平台的字节码,是由Python的虚拟机来执行的,这个是类似于Java或者.NET的虚拟机的概念,从而实现跨平台。pyc文件经过python解释器最终会生成机器码运行。所以pyc文件是可以跨平台部署的,类似Java的.class文件。如果py文件改变,也会重新生成pyc文件。
pyc的内容,是跟python的版本相关的,不同版本编译后的pyc文件是不同的,2.5编译的pyc文件,2.4版本的python是无法执行的。
Python是完全面向对象的语言,Python文件在经过解释器解释后生成字节码对象PyCodeObject,pyc文件可以理解为是PyCodeObject对象的持久化保存方式。pyo是优化的字节码文件。当python程序运行时,编译的结果是保存在位于内存中的PyCodeObject中,当Python程序运行结束时,Python解释器则将PyCodeObject写回到pyc文件中。当python程序第二次运行时,首先程序会在硬盘中寻找pyc文件,如果找到,则直接载入,否则就重复上面的过程。所以,我们可以说pyc文件其实是PyCodeObject的一种持久化保存方式。
Python选项中:
其他文件:
(1)python为了提高运行效率也会进行编译
python是解释型语言,运行的时候需要通过python解释器解释执行。我们知道解释型语言最大的问题是运行速度比编译性慢,因为编译性语言会产生二进制执行文件,也就是不跨平台的机器指令。所以如果先编译出pyc文件后,可以节省编译这一步的耗时时间。在一定程度上提高程序的运行速度。
我们一般认为C/C++是编译语言,ruby是解释型语言。而Java是先编译后解释的语言:Java首先是通过编译器编译成字节码文件,然后在运行时通过解释器给解释成机器文件。Java,.net,python等基于虚拟机的语言,我们又不能把语言纯粹地分成解释型和编译型这两种。Python也是一门基于虚拟机的语言。当我们在命令行中输入python hello.py时,其实是激活了Python的“解释器”,告诉“解释器”:你要开始工作了。可是在“解释”之前,其实执行的第一项工作和Java一样,是编译。
一般的IDE,比如Eclipse都会将这两步合并为一步。先编译后解释:
Python解释器将源码转换为字节码(跨平台,统一的,只不过不同OS的虚拟机基于它产生不同的机器指令实现跨平台),然后再由解释器来执行这些字节码,转化为合适的机器指令,然后执行。
(2)防止源码泄露。
因为py文件是可以直接看到源码的,如果你是开发商业软件的话,不可能把源码也泄漏出去吧?所以就需要编译为pyc后,再发布出去。当然,pyc文件也是可以反编译的,不同版本编译后的pyc文件是不同的,根据python源码中提供的opcode,可以根据pyc文件反编译出py文件源码,网上可以找到一个反编译python2.3版本的pyc文件的工具,不过该工具从python2.4开始就要收费了,如果需要反编译出新版本的pyc文件的话,就需要自己动手了,不过你可以自己修改python的源代码中的opcode文件,重新编译python,从而防止不法分子的破解。
实际开发中我们发现有的py文件产生pyc,而有的py文件不产生pyc。
pyc文件只有在文件被当成模块导入时才会生成。也就是说,Python解释器认为,只有import进行的模块才需要被重用。 生成pyc文件的好处显而易见,当我们多次运行程序时,不需要重新对该模块进行重新的解释。主文件一般只需要加载一次不会被其他模块导入,所以一般主文件不会生成pyc文件。
当有别的程序再次import这些模块时,python就不用再重新解析py文件,而是读入pyc文件就可以了。
因为并不是一定会产生pyc文件,所以在什么情况下产生pyc文件?如何产生?
(1)被当做模块调用的时候会自动生成pyc文件
一般是python脚本被当做模块,被其他脚本文件调用时,就会产生pyc文件,举个例子:
如果你写了一个脚本文件image.py是用来生成验证码的,如果你在index.py文件中想引用这个脚本的功能,就需要通过import导入image.py文件,然后,如果你运行index.py文件,那就会在image.py文件所在的路径生成一个image.pyc文件。
(2)对于py文件,可以执行下面命令来生成pyc文件。参数-m。
(3)通过代码来生成pyc文件。
Python提供了内置的类库来实现把py文件编译为pyc文件,这个模块就是 py_compile 模块。
compile函数原型:
compile(file[, cfile[, dfile[, doraise]]])
一般来说,我们的工程都是在一个目录下的,一般不会说仅仅编译一个py文件而已,而是需要把整个文件夹下的py文件都编译为pyc文件,python又为了我们提供了另一个模块:compileall 。使用方法如下:
import compileall
compileall.compile_dir(r'H:/game')
这样就把game目录,以及其子目录下的py文件编译为pyc文件了。来看下compile_dir函数的说明:
compile_dir(dir[, maxlevels[, ddir[, force[, rx[, quiet]]]]])
pyc文件一般由3个部分组成:
模块其实也是一个python文件。我们把一些功能相关的代码写到一个模块里。这样,当你需要用到某个功能时,就将这个模块导入,就可以直接使用它的函数了,非常的方便。
在python中,一个模块就是一个py文件,可以说一个文件就是一个独立的模块,一个独立的模块就是一个py文件。你自己写的py文件,可以引入别人的模块;别人也可以引用你的这个py文件,去使用你写的函数 。所以,模块中可以有函数,也可以有类。
导入一个模块,使用import。
python -O -m py_compile file.py
可以编译成pyo文件,是优化过的字节码文件。
1. 其中的 -m 相当于脚本中的import,这里的-m py_compile 相当于上面的 import py_compile
2. -O 如果改成 -OO 则是删除相应的 pyo文件,具体帮助可以在控制台输入 python -h 查看