转载自 【编程技巧】py文件批量编译,py批量转pyd,PyCharm设置py转pyd功能
python文件*.py都是明文,很难对代码进行加密。而python -m py_compile xxx.py的编译操作只能编译成pyc,pyc是很容易反编译的。
如果想彻底编译成二进制文件,必须用到Cython编译成pyd二进制文件。
但是使用Cython处理比较麻烦,要编写setup.py等很多设置。
本文的代码可以自动对单个py文件、目录中的所有文件(包含子目录里的py)进行自动编译,一键操作,非常便捷。还可以在集成环境PyCharm中进行一键操作。
一、运行代码
话不多说,先上代码。
参数说明请详细看注释,注释写的很全面。
注意首先Python环境要先安装cython模块:pip install cython
如下是主代码,文件名:py2pyd.py
# coding=utf-8
"""
Python批量编译程序
命令行参数说明:
all:对目录及子目录下的所有py文件进行编译
one:对单个py文件进行编译
del:编译完删除py文件。此操作无法恢复、慎用!!!
nodel:编译完不删除py文件
例子:
python py2pyd.py all del D:\PYTHON\toPYD\test
python py2pyd.py one nodel D:\PYTHON\toPYD\test\mycode.py
"""
import os, shutil, time, sys, glob
try:
from setuptools import setup # 检测是否安装了cython
except:
print("\n请先安装cython模块:pip install cython\n"); sys.exit()
python_path = "D:/work/dcc_scripts/python310/python.exe"
def py2pyd(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: # 自动生成单独的setup.py文件
write_str = """
# coding=utf-8
from Cython.Build import cythonize
from setuptools import setup, Extension, find_packages
from setuptools.command.build_ext import build_ext as _build_ext
import os
class build_ext(_build_ext):
def build_extension(self, ext):
original_get_ext_fullpath = self.get_ext_fullpath
def override_get_ext_fullpath(ext_name):
filename = original_get_ext_fullpath(ext_name)
return os.path.basename(filename)
self.get_ext_fullpath = override_get_ext_fullpath
_build_ext.build_extension(self, ext)
def copy_extensions_to_source(self):
pass
setup(
name='{}',
ext_modules=cythonize('{}', compiler_directives={{'language_level': '3'}}),
author = 'xinglian',
author_email = 'beimingxinglian@gmail.com',
cmdclass={{'build_ext': build_ext}}
)
"""
write_str = write_str.format(file_path[:-3], file_path)
f.write(write_str)
print('"{}" {}/setup.py build_ext --inplace'.format(python_path, folder_path))
os.system('"{}" {}/setup.py build_ext --inplace'.format(python_path, folder_path)) # py编译开始
filename = file_path.split('.py')[0] # 文件名
pyd_name = '%s\\%s.pyd' % (folder_path, filename) # pyd文件名
if os.path.exists(pyd_name):
os.remove(pyd_name) # 删除老的pyd
amd64_pyd = glob.glob(filename + "*.pyd") # 获取pyd文件的全名,类似***.cp38-win_amd64.pyd
if not amd64_pyd:
print(filename + "生成失败")
return
print("生成了PYD:" + amd64_pyd[0])
os.rename(amd64_pyd[0], pyd_name) # 改名字,删除多余的cp38-win_amd64.等
os.remove('%s.c' % filename) # 删除临时文件
build_folder_path = os.path.join(folder_path, 'build')
shutil.rmtree(build_folder_path) # 删除掉生成的build文件夹
os.remove('setup.py') # 删除掉生成的setup.py
if del_py == 'del': # 删除py源文件,无法恢复,慎用!
os.remove(file_path)
def get_all_file(path): # 遍历此目录下的所有py文件,包含子目录里的py
for root, dirs, files in os.walk(path):
for name in files:
if name.endswith(".py"):
file_path = os.path.join(root, name)
py2pyd(file_path)
if len(sys.argv) <= 3: # 判断命令行参数是否合法
print("\n命令行参数错误...\n");
sys.exit()
one_all, del_py, paths = sys.argv[1:4] # 获取命令行参数
if one_all == 'one':
py2pyd(paths)
else:
get_all_file(paths)
批处理测试文件:
::Python批量编译程序
::命令行参数说明:
::all:对目录及子目录下的所有py文件进行编译
::one:对单个py文件进行编译
::del:编译完删除py文件。此操作无法恢复、慎用!!!
::nodel:编译完不删除py文件
::例子:
::python py2pyd.py all del D:\PYTHON\toPYD\test
::python py2pyd.py one nodel D:\PYTHON\toPYD\test\mycode.py
python py2pyd.py all del D:\PYTHON\toPYD\test
python py2pyd.py one nodel D:\PYTHON\toPYD\test\ianx6.py
pause
二、PyCharm的自动设置
在CMD里用命令行运行py2pyd,可能比较麻烦。如果可以在PyCharm集成环境里直接编译那就太好了。如下设置可以实现。
依次点击:PyCharm->文件->设置->工具->外部工具,点击“+”,进入编辑窗口
单个文件
批量处理
程序:
python.exe
实参:
- 单个:
py2pyd.py one nodel $FileDir$\$FileName$
- 批量:
py2pyd.py all nodel $FileDir$
- 单个:
第一个参数 py2pyd.py的路径要自己修改成实际路径
如果你想编译后把py文件删除,只保留pyd文件,把nodel改成del即可,慎用!删除后不可恢复,回收站也没有的啊!