转:编译Python源代码

http://hgoldfish.mysmth.net/2010/03/18/%E7%BC%96%E8%AF%91python%E6%BA%90%E4%BB%A3%E7%A0%81/

 

在日常生活中,Python代码一般是不编译的,几个py文件复制来就能用。再加上脚本语言的名头,有些不太了解Python的朋友就以为Python没有编译这个过程。其实,虽然Python是脚本语言,但它与Java和C#一样,只能执行字节码。只是Python将编译过程隐藏起来,不大明显而已。今天这篇笔记详细记述一下Python的编译过程以及一些技巧。

我们一般使用这样的命令运行一个python程序:

C:/> python im.py

其中,im.py文件的内容是:

#!/usr/bin/env python

import mymodule

mymodule.say(”hello”)

执行这一命令后,Python解释器其实并不一定会读入mymodule.py文件,它会尝试读取mymodule.pyc文件或者mymodule.pyo文件。如果都失败了,或者mymodule.py文件比mymodule.pyc/mymodule.pyo新,才转而读入mymodule.py文件。Python只懂得解释执行字节码,所以mymodule.py文件读入后第一件事就是先进行编译。编译的结果会被尝试保存到mymodule.pyc文件中。等一下会讨论如何控制Python的编译过程。

虽然与C++/Java这样的静态语言一样,采用了编译(compile)这个术语,实际情况还是有所不同的。首先,最明显的一点,Python编译的最终结果不是机器码,而是字节码。Python的编译实际上主要是进行文法分析,生成一个抽象语法树,然后转储成字节码形式了事。

从上面的介绍可以发现Python的编译与C++相去甚远。不过倒与Java有些相像,因为它们都生成字节码。凭良心说,Java的编译过程比Python先进很多。Java的解释器在执行Java字节码的时候,会使用JIT,将循环操作等热点转化成为机器码。所以有时候Java的性能能够达到接近C++的级别。Python缺少JIT并非故意所为,而是缺少人力资源。现在已经有一个pysco的外部模块,据说能大大提高Python代码的速度,不过这个模块还没有进入Python的官方代码。

Python的字节码列表可以见此链接:

http://www.python.org/doc/2.5.2/lib/bytecodes.html

接下来,介绍一下如何“稍微”控制Python的编译过程。只所以说是稍微,是因为无论何种情况,Python都会对字节码进行一些简单优化(basic Peephole Optimization,详情参见Python的源代码。2.5版本的Python位于 Python/compile.c,2.7版本则位于Python/peephole.c)。这些优化不能通过环境变量或者命令参数将其禁用。比如:

if True:

return 1

else:

return 0

会被优化成为:

return 1

更多的优化正被添加到Python源代码内。只有三个参数能影响编译时的优化:

第一、去除所有的assert语句,并将__debug__这个内置变量的值设置为False。方法是运行Python的时候在命令行添加参数:

python -O im.py

第二、除了第一条所做的事情,还去除所有docstring。方法是运行Python的时候在命令行添加参数:

python -OO im.py

第三、默认的,对于一个模块,编译后的字节码会被保存到与源代码相同的文件夹内。这样就可以加速模块的载入速度。大多数使用Python的朋友们都写过包含两三个文件的程序。通常可以发现除了.py文件之外,文件夹内还会有.pyc文件。mymodule.pyc文件即是mymodule.py的字节码。如果运行Python的命令行包含了”-O”或者”-OO”参数,Python会将优化后的字节码保存到mymodule.pyo文件。想要禁止生成.pyc或者.pyo文件,可以在运行Python的时候,在命令行里添加参数:

python -B im.py

还可以设置环境变量:

c:/> set PYTHONDONTWRITEBYTECODE=x

看完上面三条说明,有的朋友可能会疑问,”-O”和”-OO”参数真的就干那三件事?不幸的是,还真是如此。至少在Python2.5的时候就是这样。所以加”-O”参数并不能明显优化Python的运行速度。这两个选项的真正作用是区分调试版本和发行版本。在程序中可以尽量多增加一些assert语句,以便程序员在调试阶段发现一些隐藏的错误。而在发布时,将这些语句去除。如果你的软件是商业软件的话,加上”-OO”参数可以让别人看不清内部函数的用途,增加一些破解的难度。有了这些,谁还说Python不能写商业软件?

说到商业软件,不得不说到反编译工具。很神奇的一件事,Python内置了反编译的模块!囧rz,使用方法也很简单:

>>> import mymodule

>>> import dis

>>> dis.dis(mymodule) #打印出反编译的结果

反编译后的代码与汇编语言接近,所以想要破解Python商业软件还是有一定难度的。据说还有一些工具能够反编译出漂亮的Python源代码,我并没有亲见。

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值