Python编译相关知识有哪些
小编给大家分享一下Python编译相关知识有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!
Python是一门能快速开发的解释型语言
Python和Java的解释方式对比
Java:源代码 -> 编译成class -> Jvm解释运行
Python:源代码 -> Python解释器解释运行
事实上,Python和Java的解释方式是相同的,只是我们表面上看Python是直接解释源代码,而实际上python解释器只会加载字节码。细心的小伙伴肯定发现了这一点,当我们import某个模块时,总是会在模块所在的目录创建一个__pycache__目录,里面存放着被加载模块的字节码文件
编译源代码有以下作用:
源代码保护(算法保护)
防止用户篡改源代码解释器加载代码速度加快
Python的几种文件类型
py:Python控制台程序的源代码文件
pyw:Python带用户界面的源代码文件
pyx:Python包源文件
pyc:Python字节码文件
pyo:Python优化后的字节码文件
pyd:Python的库文件(Python版DLL)、在Linux上是so文件
pyc和pyo的生成方法
pyc的作用是用来跨平台使用的,和Java中的Class文件类似。pyc文件是一种字节码文件,可以加快Python解释器的加载速度,当然也可以用来做简单的防源码泄露保护。
pyo则是优化过后的字节码文件,不过pyo更像编译型语言里的中间文件。
我们可以通过Python提供的py_compile模块来进行源代码的编译。
py_compile模块只提供3个方法,分别是有关编译异常PyCompileError、有关编译compile、有关程序入口main
我们要用到的是compile方法,compile原形如下:
compile(file, cfile=None, dfile=None, doraise=False, optimize=-1)
有5个参数:
file:必选参数,要编译的源文件
cfile:编译后的文件,默认在源文件目录下的__pycache__/源文件名.解释器类型-python版本.字节码类型
### 例如:__pycache__/abc.cpython-34.pyo
dfile:错误消息文件,默认和cfile一样
doraise:是否开启异常处理,默认False
optimize:优化字节码级别
optimize为1时,优化字节码级别为最高 -1和0:设置pyc优化级别 1和2:设置pyo优化级别 数字越小,优化级别越高
准备源文件a.py和b.py,内容相同,就是一句print("python")代码
编写编译脚本:
import py_compile py_compile.compile(file = "a.py",cfile = "a.pyc",optimize=-1) py_compile.compile(file = "b.py",cfile = "b.pyo",optimize=1)
运行后可以看到已经成功编译成字节码文件了,分别为a.pyc和b.pyo。
尝试运行这2个字节码文件:
python a.pyc python a.pyo
字节码文件成功运行。
也可以直接通过Python加载模块来运行:
#编译成pyc
python -m py_compile 源代码
#编译成pyo
python -O -m py_compile 源代码
这确实可以简单地保护我们的代码,同时似乎看起来像是加密的效果,但是要注意,这不是加密,只是把源码变成优化后的字节码而已,如果想要获得源码,我们一样可以通过逆向编译来得到源码,目前有专门逆向Python字节码的工具存在。
如果需要编译整个目录内的所有源代码,请参考Python compileall
pyd可以让我们的代码更安全
如果真的想要保护代码,为何不考虑把它变成python扩展模块?(目前还没有pyd被反编译的消息)
pyd是Python中的扩展模块,相当于windows的dll,不同的是pyd只供python调用而已。
实际上,大部分的包、小模块都是以pyd形式发布的。
如果特别感兴趣的小伙伴可以深入研究下setuptools和distutils
在把源代码转换成功pyd之前,我们需要用到Cython包。
pip list | findstr "Cython"
检查是否安装了Cython,没有请pip install Cython安装即可
编译pyd步骤1:生成C代码
import Cython.Build
#导入Build模块
Cython.Build.cythonize("a.py")
#a.py转换成C代码
cythonize运行完成之后,无异常的情况下会在a.py的目录下创建一个a.c文件,同时会返回一个distutils.extension.Extension对象列表
一定要注意的是:如果在Python Shell测试,一定要用绝对路径,否则会ValueError异常,cythonize不会从sys.path中读路径。
编译pyd步骤2:利用distutils生成pyd扩展模块
此时我们可以用distutils包来编译成我们要的pyd模块
编译a.py成pyd
import Cython.Build
import distutils.core
a = Cython.Build.cythonize("a.py")
#返回distutils.extension.Extension对象列表
distutils.core.setup(
name = 'pyd的编译',#包名称
version = "1.0",#包版本号
ext_modules= a,#扩展模块
author = "Happyran", #作者
author_email='happyran163@163.com' #作者邮箱
)
python 执行编译的脚本 build
或
python 执行编译的脚本 build_ext
此时会在编译脚本所在目录生成一个build目录,里面存着C语言的.def文件和.o文件,还有我们要的pyd文件
批量编译pyd文件的误区
此时我们已经生成了1个pyd文件,如果我们是扩展包/模块的开发者,怎么批量编译呢?
总有人会犯错,例如以下2个例子:
a = Cython.Build.cythonize("a.py")
b = Cython.Build.cythonize("b.py")
distutils.core.setup(
...,
ext_modules= [a,b]
)
这样做吗?NO......
a = Cython.Build.cythonize("a.py")
a.append(Cython.Build.cythonize("b.py"))
distutils.core.setup(
...,
ext_modules= a
)
还是这样?
犯这样的错原因却是因为:
a = Cython.Build.cythonize("a.py")
type(a)
提示<class 'list'>
没错,Cython.Build.cythonize返回的是一个列表,里面只有1个distutils.extension.Extension对象
会报错,需要1个Extension或者是2个元组
批量编译pyd
方法1:提取我们要的Extension对象
import Cython.Build
import distutils.core
a = Cython.Build.cythonize("a.py")[0] #提取Extension对象
b = Cython.Build.cythonize("b.py")[0]
distutils.core.setup(
name = 'pyd的编译', #包名称
version = "1.0", #包版本号
ext_modules= [a,b], #被扩展的模块
author = "Happyran", #作者
author_email='happyran163@163.com' #作者邮箱
)
方法2:转换成C代码后再进行Extension对象实例化
import Cython.Build
import distutils.core
Cython.Build.cythonize("a.py")
Cython.Build.cythonize("b.py")
distutils.core.setup(
name = 'pyd的编译', #包名称
version = "1.0", #包版本号
ext_modules= [distutils.core.Extension('a',["a.c"]),distutils.core.Extension('b', ['b.c'])], #被扩展的模块
#[
#distutils.core.Extension('a',["a.c"]),
#distutils.core.Extension('b', ['b.c'])
#]
author = "Happyran", #作者
author_email='happyran163@163.com' #作者邮箱
)
pyc和pyo相对而言安全性较低,pyd是目前解决Python开发中代码安全性最优的一个方案。
但是要注意一点:无论是pyc还是pyo、pyd,都是跟着Python版本走的,不要指望Python2.7的东西在Python3上完美运行。
PS:如果遇到running build...提示,删掉build目录重新编译即可。
以上是“Python编译相关知识有哪些”这篇文章的所有内容,感谢各位的阅读!相信大家都有了一定的了解,希望分享的内容对大家有所帮助,如果还想学习更多知识,欢迎关注行业资讯频道!