我们编写的程序源代码,或者下一个小的脚本文件需要对外发布时,我们有时候不想让别人能轻易地看到我们的源码,可以将其编译成pyd形式地进行外发,pyd相对于pyc和pyo编译文件,他们两种文件形式差不多,也很容易被反编译,pyd格式是D语言(C/C++综合进化版本)生成的二进制文件,实际也是DLL文件,这种格式文件目前好像是没有可以反编译的消息,只能反汇编。这种文件区别于打包成exe是它生成的pyd文件还可以是原来项目的目录结构,对于项目开发者来说释放出去之后出现问题也方便定位。废话多说,上代码比较。
以获取当前工作目录的代码为例,我们对比一下pyc文件和pyd文件的区别
源码 假定文件是current_path.py
1 import time 2 import os 3 4 while 1: 5 time.sleep(1) 6 print(os.getcwd())
在该文件的目录下打开python解释器执行
可以看到在当前目录下生成一个__pychache__的文件夹,打开会有一个同名的pyc文件
打开之后,
还是多少能看到点源码的,这个就违背了不想让人看到源码的初衷了,我们再来看下生成的pyd文件,
这就很nice了。下面介绍具体方法:
1、安装Cython,python下很简单,pip3 install cython 即可
2、准备源文件、即上面的current_path.py
3、准备打包文件 set_up.py 内容如下
from distutils.core import setup from Cython.Build import cythonize setup(ext_modules=cythonize("set_up.py"))
4、在当前目录下执行
python set_up.py build_ext --inplace
5、报错 Unable to find vcvarsall.bat
解决办法 安装Visual studio 官网下载社区版即可安装时选择Python开发进行安装(下图是找的,自己安装的时候忘记截图了,懒得截了)
python setup.py build_ext --inplace
在超过二级目录的时候会额外多一级目录,目前还没有好的办法解决,希望看到这例的读者能提供一个好的建议。再有就是如果项目中出现了同名的set_up.py时,要记得单独编译一下。
将其重命名,去掉 cp37-win_amd64.,将其移动到源文件位置删除源文件,就可以使用了,但是不是直接执行该文件,而是去另外一个文件例去导入该文件的函数或者类,执行另外一个py文件,这时候就执行成功了。跟正常的源文件一样,这时候就满足了需求。
上述是单个打包成pyd文件,但是批量打包的话这样做很难受,我看到的只是批量生成pyc文件的命令,但是没有批量生成pyd文件的命令,于是自己就写了一段程序供大家参考,代码如下 create_pyd_file.py
#!/usr/bin/env python # -*- coding:utf-8 -*- # @time: 2021/5/26 14:17 # @File: create_pyd_file.py import os import shutil import time import sys def func(path): folder_path = os.path.dirname(path) file_path = os.path.split(path)[1] os.chdir(folder_path) with open('setup.py', 'w') as f: f.write('from setuptools import setup\n') f.write('from Cython.Build import cythonize\n') f.write('setup(\n') f.write("name='test',\n") f.write("ext_modules=cythonize('%s')\n" % file_path) f.write(")\n") os.system('python setup.py build_ext --inplace') filename = file_path.split('.py')[0] time.sleep(2) # 这里的cp37-win_amd64需要注意一下,这个是依据python解释器类型以及windows版本生成的,建议是单个生成一个pyd文件然后相应修改一下 os.rename('%s\\%s.cp37-win_amd64.pyd' % (folder_path, filename), '%s\\%s.pyd' % (folder_path, filename)) # 这个是删除py源文件,测试的时候可以先注释掉查看效果 os.remove('%s.c' % filename) build_folder_path = os.path.join(folder_path, 'build') # 删除掉生成的build文件夹 shutil.rmtree(build_folder_path) os.remove('setup.py') os.remove(file_path) def get_all_file(path): for root, dirs, files in os.walk(path): for name in files: if name.endswith(".py"): file_path = os.path.join(root, name) func(file_path) paths = sys.argv[1] get_all_file(paths)
调用的方法是在该文件当前路径下执行 加上项目的绝对路径 比如
python create_pyd_file.py D:\python_demo\demo
测试的时候在windows以及ubuntu上二级目录都可以编译成pyd文件并替换到原来的位置 现在有点问题的就是再深层级的目录就出现问题了,原因是这条命令
更多精彩,可以关注楼主的公众号,
最全面的django面试题总结: 回复django面试题即可获取, pycharm供给激活压缩包, 回复pycharm破解包即可获取,破解步骤在我的这一篇博客(点我直达)已经破解百次, 屡试不爽.
以及其他楼主精心打造的原创文章,欢迎各位来访.