2022.2.21更新
- python程序执行效率是明显低于c的。
- 优化python代码的一个思路就是:将python的核心代码(一般是需要多次调用,或核心循环部分)转换成c语言。
- 不需要将程序重新改写成c,只需要用Cython包将python程序进行转换即可。
1.Cython包
- Cython包的安装参见https://pypi.org/project/Cython/
pip install Cython
conda install Cython
- 一般安装anaconda的时候就带有Cython包;可以查看一下是否已经有这个包了。(直接在程序里
import Cython
,若不报错就说明有;也可以通过pip list等查看)
2.python–>c
2.1
- 将需要转换的程序重命名为
xxxx.pyx
;
例如我有一个封装好的类.py文件word_frequency.py
,需要重命名为word_frequency.pyx
2.2
- 在相同的目录中创建一个文件
setup.py
;作用:使用cython编译器去编译pyx文件
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize("word_frequency.pyx"))
2.3
-
开始编译,在命令行中:
python setup.py build_ext --inplace
(# inplace表示源代码在同一目录下) -
若编译成功,则在目录下会出现两个文件:
word_frequency.c
,word_frequency.cp38-win_amd64.pyd
(若在Linux平台下会出现word_frequency.cp38-win_amd64.so
),此时.so文件或者.pyd文件就可以像普通的python文件一样,被import。 -
上述文件中
word_frequency.c
没有什么用,可以删除掉;word_frequency.cp38-win_amd64.pyd
文件可以重命名为word_frequency.pyd
。不重新命名也可以,载入from word_frequency import word_frequency
不受影响。
2.4
- 在其他文件中正常调用
word_frequency.pyd
即可(可以将word_frequency.py
改为其他名字,以免调用错)。
from word_frequency import word_frequency #一样的import
wordFreq = word_frequency(dict_fullpath) #一样的使用方法
2.5
- 对比
转换前:130.40097641944885 s
转换后:68.84645509719849 s
- 速度只提升了一倍左右。
- Cython能比常规Python代码快多少实际上取决于代码本身。例如,如果运行成本较高的多变量循环,Cython明显优于常规的Python代码。递归函数同样使得Cython快于Python。
3 关于.pyd文件
- 若想对python文件进行加密,会把python模块编译成.pyd文件
- pyd文件是由 D语言编写的一种dll 文件,目前还没有办法进行反编译,只能被反汇编。给python文件提供了很高的安全性。而且也可以编写一些python插件,方便python开发。
2022.2.22更新
4、python版本对.pyd文件加载的影响
出错点1:
- 1)在python3.8.8版本将
word_frequency.pyx
编译成word_frequency.cp38-win_amd64.pyd
。 - 2)在python3.8.8版本中,
word_frequency.cp38-win_amd64.pyd
能够被其他文件正常载入;from word_frequency import word_frequency
没有问题。 - 3)当把
word_frequency.cp38-win_amd64.pyd
移植到python3.7.4版本的电脑上时,from word_frequency import word_frequency
会出现如下错误:
“我以为是高版本的python 编译的内容无法被低版本的python加载”
“所以,我把编译和加载的版本换了一下(移植顺序换了一下)”
出错点2:
- 1)在python3.7.4版本将
word_frequency.pyx
编译成word_frequency.cp37-win_amd64.pyd
。 - 2)在python3.7.4版本中,
word_frequency.cp37-win_amd64.pyd
能够被其他文件正常载入;from word_frequency import word_frequency
没有问题。 - 3)当把
word_frequency.cp37-win_amd64.pyd
移植到python3.8.8版本的电脑上时,from word_frequency import word_frequency
同样会出现如下错误:
“所以,可能并不是高低版本兼容的问题”
“只能在对应的python版本上编译,然后加载运行;这意味着必须在本地编译,这就给用户操作上带来了一些麻烦;需要简化”
“将编译的代码也放在getWordFreq_Month.py
中,虽然是本地编译,但是不需要用户操作命令行,即用户和原来的使用方法一样”
改善:
- 在
getWordFreq_Month.py
中添加如下代码,(也要保证setup.py
和word_frequency.pyx
在相同目录下)
#将word_frequency.py编译成c
flag = True
file_list = os.listdir('./')
for file_name in file_list:
#文件后缀是否有'.pyd'的
file_suffix = os.path.splitext(file_name)[1]
if file_suffix == '.pyd':
flag = False
#判断是否需要在本地重新编译
if flag:
try:
os.system('python setup.py build_ext --inplace')
except:
try:
os.system('python3 setup.py build_ext --inplace')
except:
print('编译c存在问题!')
sys.exit(0)
#加载
from word_frequency import word_frequency
2022.2.23更新
5.如何彻底解决.pyd文件在其他python版本上无法加载的问题
出错点:
- 1)虽然第4步的操作,把编译成c的过程放在了每台主机本地了,但是在一台python3.9版本的主机上,依然报错了:
- 2)在一台python3.6版本的主机上也出现了错误:
- 3)两个错误均是
Unable to find vcvarsall.bat
,查了一下vcvarsall.bat
这个文件好像还和visual stdio相关,比较麻烦。 - 4)出错的地方还是在编译的地方,就是
python setup.py build_ext --inplace
这句命令会出错。
“所以,虽然吧编译的程序放在了每台主机上,但是仍然会存在各种问题,移植性还是不好。”
“既然移植性不好搞定,那就直接封死吧,不再依赖python”
改善:
用pyinstaller将getWordFreq_Month.py
文件封装成getWordFreq_Month.exe
,可以脱离python环境。
- 安装pyinstaller
pip install pyinstaller
- 在.py目录中执行如下命令行:
pyinstaller -F getWordFreq_Month.py #-F 选项,该选项指定生成单独的 EXE 文件,因此,在 dist 目录下生成了一个单独的大约为 6MB 的 xxxx.exe 文件
或者
pyinstaller -D getWordFreq_Month.py #当生成完成后,将会在 xxxx目录下看到多了一个 dist 目录,并在该目录下看到有一个 xxxx 子目录,在该子目录下包含了大量 .dll 文件和 .pyz 文件,它们都是 xxxx.exe 程序的支撑文件。
via:手把手教你把Python代码转成exe
Python PyInstaller安装和使用教程(详解版)
- 执行xxxx.exe时,结果会一闪而过,所以需要通过命令来显示.exe文件的输出。在写一个start.bat文件,内容:
@echo off
dist\getWordFreq_Month\getWordFreq_Month.exe
pause
完工!
参考: