深入理解python虚拟机:pyc文件结构本文主要介绍.py文件编译后对应的pyc文件结构,一个核心的pyc文件,内容是python字节码。pyc文件pyc文件是Python在解释和执行源代码时生成的字节码文件。它包含源代码的编译结果和相关的元数据信息,以便Python可以更快地加载和执行代码。Python是一种解释型语言,它不像编译型语言那样直接将源代码编译成机器码执行。Python解释器在运行代码之前将源代码编译成字节码,然后解释字节码执行。.pyc文件就是这个过程中生成的字节码文件。Python解释器在第一次执行一个.py文件时,会在同一目录下生成一个对应的.pyc文件,以便下次加载时执行速度更快。如果源文件在修改后重新加载,解释器会重新生成.pyc文件以更新缓存的字节码。生成pyc文件一个普通的python文件需要通过编译器转换成字节码,然后将字节码交给python虚拟机,然后由python虚拟机执行字节码。整体流程如下:我们可以直接使用compileall模块生成对应文件的pyc文件。?pvmlsdemo.pyhello.py?pvmpython-mcompileall.Listing'.'...Listing'./.idea'...Listing'./.idea/inspectionProfiles'...编译'./demo.py'...编译'./hello.py'...?pvmls__pycache__demo.pyhello.py?pvmls__pycache__demo.cpython-310.pychello.cpython-310.pycpython-mcompileall。该命令会递归扫描当前目录下的py文件,生成对应的pyc文件。pyc文件布局magicnumber的第一部分由两部分组成:magic的第一部分由一个2字节的整数和另外两个字符回车和换行组成,“\r\n”也占两个字节,共四个字节。这个两个字节的整数在不同的python版本中是不同的。例如python3.5中为3351,python3.9中为3420、3421、3422、3423、3424(Python3.9中的Minorversion)。第二部分BitField的主要作用是复现以后的编译结果,但是在python3.9a2中,这个字段的值都是0,具体可以参考PEP552-Deterministicpycs。python2和python3早期版本不存在该字段(python3.5还没有),python3以后版本才出现该字段。第三部分是整个py源文件的大小。第四部分也是整个pyc文件中最重要的部分。最后一部分是CodeObject对象的序列化数据。我们稍后会分析与此对象相关的数据。我们现在来分析一个pyc文件。对应的python代码为:deff():x=1return2pyc文件的十六进制形式如下:?__pycache__hexdump-Chello.cpython-310.pyc000000006f0d0d0a00000000b948216420000000|o.....H!d...|00000010e3000000000000000000000000000000|。.........|00000020000200000040000000730c0000006400|......@...s...d。|00000030640184005a0064025300290363000000|d...Z.d.S.).c...|000000400000000000000000000100000001|000.........|000000500043000000730800000064017d006402|.C...s....d.}.d.|00000060530029034ee901000000e902000000a9|S.).N.........|00000070002901da017872030000007203000000|.)...xr....r....|00000080fa0a2e2f68656c6c6f2e7079da016601|.../hello.py..f.|0000009000000073040000000401040172060000|...s.....r...|000000a0004e2901720600000072030000007203|.N).r...r...r.|000000b000000072030000007205000000da083c|...r...r......<|000000c06d6f64756c653e010000007302000000|module>....s....|000000d00c00|..|000000d2因为数据使用小端表示,所以对于上面的数据:幻数的第一部分是:0xa0d0d6f,位域的第二部分是:0x0。第三部分最后修改日期为:0x642148b9。第四部分的文件大小为:0x20字节,也就是说hello.py的文件大小为32字节。下面是读取pyc文件头元信息的一小段代码:unpack('
