我们每天编写的Python、Java、C++等代码通常指的就是源代码,源代码的特点是人类可读。但是CPU只能读懂二进制,看不懂我们写的源代码,因此还需要进行编译(compile)
因为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’
机器码是CPU可直接解读的代码,也称为native code。
在Python中,解释器是一种让Python程序运行起来的程序,在IDE中可以看到对解释器进行选择。
生成了字节码之后,就会被发送到Python虚拟机(Python virtual machine, PVM)中执行,因此Python虚拟机是Python解释器的最后一步。Python虚拟机
对于一个*.py文件,在执行过程中解释器会先把*.py文件编译为字节码,并缓存在*.pyc文件中;
编译产生的字节码被python虚拟机逐行执行
Python 解释器是真的一行一行读取 Python 源代码而后执行吗? 实际上,Python 在执行程序时和 Java、C# 一样,都是先将源码进行编译生成字节码,然后由虚拟机进行执行,只不过 Python 解释器把这两步合二为一了而已。
这个背后的逻辑和Java是一样,主要是为了解决跨平台性。Java的执行过程也是先把源代码编译为字节码,然后进入Java虚拟机进行执行。Java虚拟机会屏蔽掉不同操作系统以及CPU之间的差异,因此解决跨平台性的问题。
虽然提升了跨平台性,却因为中间码的存在降低了运行速度。Python如何解决这一问题呢?Python在下一次执行时,会检查源代码文件(.py)文件与字节码文件(.pyc)的时间戳,如果时间戳一致,说明源代码没有修改,那么就会跳过对源代码的编译过程而直接加载字节码进入虚拟机执行。如果时间戳不一致,才会重新编译。而字节码的执行相对较快,这样就大大缩短了项目运行前的准备时间
最近在编写Python脚本过程中遇到一个问题比较奇怪:Python脚本正常的,但执行报错**“AttributeError: module ‘xxx’ has no attribute ‘xxx’”**,
其实是.pyc文件存在问题
附录:
pyc文件介绍
pyc文件,是python编译后的字节码(bytecode)文件。只要你运行了py文件,python编译器就会自动生成一个对应的pyc字节码文件。这个pyc字节码文件,经过python解释器,会生成机器码运行(这也是为什么pyc文件可以跨平台部署,类似于java的跨平台,java中JVM运行的字节码文件)。下次调用直接调用pyc,而不调用py文件。直到你这个py文件有改变。python解释器会检查pyc文件中的生成时间,对比py文件的修改时间,如果py更新,那么就生成新的pyc。
find . -name "*.pyc" | xargs /bin/rm -rf