1.什么是__pycache__文件
用python编写好一个工程,在第一次运行后,总会发现工程根目录下生成了一个__pycache__文件夹,里面是和py文件同名的各种*.pyc或者*.pyo文件
。名字上看应该是相应的缓存文件。
那为什么会出现__pycache__文件,和Python解释器有关
Python程序运行时不需要编译成二进制代码,而直接从源码运行程序,简单来说是,Python解释器将源码转换为字节码,然后再由解释器来执行这些字节码。
解释器的具体工作:
- 完成模块的加载和链接
- 将源代码编译为PyCodeObject对象(即字节码),写入内存中,供CPU读取
- 从内存中读取并执行,结束后将PyCodeObject写回硬盘当中,也就是复制到.pyc或.pyo文件中,以保存当前目录下所有脚本的字节码文件
之后若再次执行该脚本,它先检查【本地是否有上述字节码文件】和【该字节码文件的修改时间是否与其脚本一致】。是就直接执行,否则重复上述步骤。
2.为什么会出现__PYCACHE__文件夹
python解释器会将 *.py 脚本文件进行编译,并将编译结果保存到__pycache__目录中。
下次再执行工程时,若解释器发现这个 *.py 脚本没有修改过,就会跳过编译这一步,直接运行以前生成的保存在 __pycache__文件夹里的 *.pyc 文件。
这样工程较大时就可以大大缩短项目运行前的准备时间;如果你只需执行一个小工程,没关系忽略这个文件夹就行。
3.什么时候会出现__PYCACHE__文件夹
工程目录下有__main__.py文件,和其他将要调用的模块时。如果只有当前运行的脚本
“main”,则不会生成 pycache 的文件。
4.python编译代码流程
4.1 源代码(source code)
我们自己编写的Python、Java、C++等代码通常指的就是源代码,源代码的特点是人类可读。但是CPU只能读懂二进制,看不懂我们写的源代码,因此还需要进行编译(compile)。
4.2 字节码(byte code)
因为CPU读不懂源代码,因此需要对源代码进行编译:把源代码(原始语言)转换成另一种编程语言(目标语言)的过程称为编译。但是在Python中,并不是直接把源代码编译为机器码的。还需要经历一个中间语言,即字节码。字节码以字节的形式方式存储,如
b'd\x00Z\x00e\x01e\x02e\x00\x83\x01\xa0\x03\xa1\x00e\x00d
\x01\x83\x03Z\x04e\x04j\x05Z\x06e\x07d\x02e\x06\x9b\x00\x9d
\x02\x83\x01\x01\x00d\x03S\x00'
4.3 机器码(machine code)
机器码是CPU可直接解读的代码,也称为native code。机器码就是计算机可以直接执行,并且执行速度最快的代码。
4.4 解释器(interpreter)
在Python中,解释器是一种让Python程序运行起来的程序,在IDE中可以看到对解释器进行选择。
4.5 虚拟机(virtual machine)
生成了字节码之后,就会被发送到Python虚拟机(Python virtual machine, PVM)中执行,因此Python虚拟机是Python解释器的最后一步。
5. Python工作机制
对于一个*.py文件,在执行过程中解释器会先把*.py文件编译为字节码,并缓存在*.pyc文件中;
编译产生的字节码被python虚拟机逐行执行
5.1为什么要有__pycache__文件夹?
如上文所说,字节码缓存在*.pyc文件中,而__pycache__文件夹正是缓存*.pyc地方。
*.pyc文件的命名格式是<module>.<interpreter_version>.pyc,如下图所示。
注意,对于被导入的module才会生成对应的*.pyc文件,
因此下图中虽然执行的是python ./demo.py,但是并没有看到有demo.cpython-39.pyc文件生成。
那么最根本的问题来了,为什么要这么做呢?为什么要设置一个中间代码呢?这个背后的逻辑和Java是一样,主要是为了解决跨平台性。Java的执行过程也是先把源代码编译为字节码,然后进入Java虚拟机进行执行。Java虚拟机会屏蔽掉不同操作系统以及CPU之间的差异,因此解决跨平台性的问题。
虽然提升了跨平台性,却因为中间码的存在降低了运行速度。Python如何解决这一问题呢?Python在下一次执行时,会检查源代码文件(*.py)文件与字节码文件(*.pyc)的时间戳
,如果时间戳一致,说明源代码没有修改,那么就会跳过对源代码的编译过程而直接加载字节码进入虚拟机执行。如果时间戳不一致,才会重新编译。而字节码的执行相对较快,这样就大大缩短了项目运行前的准备时间。