Python3 pyc文件详解:原理、生成与执行指南
本文详解Python3中pyc文件的原理与用途。pyc是Python编译生成的跨平台字节码,能提升加载速度并辅助隐藏源码。文章介绍了通过模块引入自动、py_compile手动编译单个文件、compileall批量编译以及命令行三种生成方式,并说明了pyc文件的执行方法。
什么是pyc文件
pyc是一种二进制文件,由py文件编译生成,属于字节码(byte code)形式。生成pyc文件后,程序加载速度会有所提升。作为一种跨平台的字节码,pyc由Python虚拟机执行,其概念类似于Java或.NET中的虚拟机机制。需要注意的是,pyc的内容与Python版本紧密相关,不同版本编译出的pyc文件存在差异,例如由2.5版本编译的pyc文件无法在2.4版本的Python环境中执行。
为什么需要pyc文件
这一需求显而易见,因为py文件直接包含可读的源码。若开发商业软件,直接发布py文件可能导致源码泄露。因此,通常将代码编译为pyc后再进行发布。尽管pyc文件理论上可被反编译,且不同版本的pyc文件结构不同,但基于Python源码中的opcode,仍有可能通过工具反编译出py文件源码。网上存在针对Python 2.3版本pyc文件的反编译工具,但从Python 2.4版本开始该工具转为收费。若需反编译更新版本的pyc文件,可能需要自行开发工具(目前尚不具备此能力)。此外,可通过修改Python源码中的opcode文件并重新编译Python解释器,以增强防破解能力。
生成pyc
一、引入模块、包生成
当模块或包被其他模块引入时,执行引入操作便会生成pyc文件(此为被动生成)。在Python 2中,pyc文件生成在当前目录;而在Python 3中,会在当前目录新建一个__pycache__文件夹,并将生成的pyc文件存放于该文件夹内。
二、代码编译生成
1. 单个文件
Python提供了内置库来实现将py文件编译为pyc文件,该模块为py_compile模块。
使用方法十分简单,如下所示,直接在idle环境中即可将py文件编译为pyc文件。
>>> import py_compile >>> py_compile.compile(r'/Users/zhangyi/Downloads/md5.py') '/Users/zhangyi/Downloads/__pycache__/md5.cpython-37.pyc' >>> Geek-Mac:__pycache__ zhangyi$ ls md5.cpython-37.pyc
compile函数原型:
compile(file[, cfile[, dfile[, doraise]]])
file参数表示需要编译的py文件路径。
cfile参数表示编译后生成的pyc文件名称及路径,默认为在file文件名后添加c或o后缀,其中o表示优化的字节码。
dfile参数的具体含义原文未完全阐明,敬请指正。原文说明:it is used as the name of the source file in error messages instead of file(该参数用于在错误信息中替代file作为源文件名显示)。
doraise参数可取True或False两个值。若为True,编译出错时会引发PyCompileError异常;若为False(默认值),编译出错时错误信息将显示在sys.stderr中,而不会引发异常。
2. 多个文件
通常情况下,工程项目位于同一目录下,我们往往需要编译整个文件夹下的py文件,而不仅仅是一个。为此,Python提供了另一个模块:compileall。使用方法如下:
>>> import compileall >>> compileall.compile_dir(r'/Users/zhangyi/Downloads/MainText') Listing '/Users/zhangyi/Downloads/MainText'... Listing '/Users/zhangyi/Downloads/MainText/.idea'... Listing '/Users/zhangyi/Downloads/MainText/.idea/inspectionProfiles'... Compiling '/Users/zhangyi/Downloads/MainText/Api.py'... Compiling '/Users/zhangyi/Downloads/MainText/Block.py'... Compiling '/Users/zhangyi/Downloads/MainText/JieBa.py'... Compiling '/Users/zhangyi/Downloads/MainText/Login.py'... Compiling '/Users/zhangyi/Downloads/MainText/Lxml.py'... Compiling '/Users/zhangyi/Downloads/MainText/Mat.py'... Compiling '/Users/zhangyi/Downloads/MainText/Myre.py'... Compiling '/Users/zhangyi/Downloads/MainText/NLP.py'... Compiling '/Users/zhangyi/Downloads/MainText/Post.py'... Compiling '/Users/zhangyi/Downloads/MainText/Text.py'... Compiling '/Users/zhangyi/Downloads/MainText/get_project_url.py'... Compiling '/Users/zhangyi/Downloads/MainText/headless_chrome_Test1.py'... Compiling '/Users/zhangyi/Downloads/MainText/headless_chrome_Test2.py'... Compiling '/Users/zhangyi/Downloads/MainText/learning.py'... Compiling '/Users/zhangyi/Downloads/MainText/nsfc.py'... Compiling '/Users/zhangyi/Downloads/MainText/re.py'... Compiling '/Users/zhangyi/Downloads/MainText/spider_image.py'... Compiling '/Users/zhangyi/Downloads/MainText/unit.py'... True >>> Geek-Mac:__pycache__ zhangyi$ pwd /Users/zhangyi/Downloads/MainText/__pycache__ Geek-Mac:__pycache__ zhangyi$ ls Api.cpython-37.pyc Text.cpython-37.pyc Block.cpython-37.pyc get_project_url.cpython-37.pyc JieBa.cpython-37.pyc headless_chrome_Test1.cpython-37.pyc Login.cpython-37.pyc headless_chrome_Test2.cpython-37.pyc Lxml.cpython-37.pyc learning.cpython-37.pyc Mat.cpython-37.pyc nsfc.cpython-37.pyc Myre.cpython-37.pyc re.cpython-37.pyc NLP.cpython-37.pyc spider_image.cpython-37.pyc Post.cpython-37.pyc unit.cpython-37.pyc Geek-Mac:__pycache__ zhangyi$
这样即可将MainText目录及其子目录下的py文件全部编译为pyc文件。接下来查看compile_dir函数的说明:
compile_dir(dir[, maxlevels[, ddir[, force[, rx[, quiet]]]]])
dir参数表示需要编译的文件夹位置。
maxlevels参数表示递归编译子目录的层数,默认为10层,即默认会编译10层子目录中的py文件。
ddir参数的具体含义原文未完全阐明。原文说明:it is used as the base path from which the filenames used in error messages will be generated(该参数用作生成错误信息中文件名的基础路径)。
force参数若为True,则强制编译为pyc文件,即使现有的pyc文件已是最新状态。pyc文件中包含时间戳,Python编译器会根据时间戳判断是否需要重新生成pyc文件。
rx参数表示一个正则表达式,可用于排除不需要的目录,或指定仅编译符合条件的目录。
quiet参数若为True,则编译完成后不会在标准输出中打印信息。
三、通过 Python Shell 命令生成
直接通过命令行运行,可以看到以下命令中并未直接调用compile()函数,这是因为py_compile模块的main()函数内部调用了compile()。
python3 -m py_compile md5.py python3 -O -m py_compile md5.py
-O参数表示优化成字节码。
-m参数表示将后面的模块作为脚本运行。
-OO参数表示在优化的同时删除文档字符串。
若想查看compile()、compile_dir()、compile_path()具体每个参数的作用,可使用print py_compile.compile().__doc__进行查看,或直接打开py_compile.py、compileall.py文件阅读源码。
运行pyc文件
直接运行即可!
Geek-Mac:__pycache__ zhangyi$ python3 md5.pyc tokenKey ==> 696f6d1af498db3c54ffa572a2723cb7 timeStamp ==> 1530954550 find ==> 100 Geek-Mac:__pycache__ zhangyi$
总结
通过上述方法,可以方便地将py文件编译为pyc文件,从而实现部分源码隐藏,保证Python在开发商业化软件时的部分安全性。后续可继续学习如何修改opcode以进一步增强安全性。
以上这篇对Python3 pyc 文件的使用详解就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持本站。
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









