功能
将Python工程目录下的所有py文件(递归所有子目录)编译成pyc文件,可选择生成新的工程目录,也可以选择删除源文件,仅保留pyc文件用于部署
pyc部署优点
省去了Python动态编译的过程,直接加载pyc字节码文件,可以加速Python运行速度。
pyc文件是二进制文件,可以保护源代码不被看见,当然也有大牛能反编译。
编译代码
import datetime
from pathlib import Path
import os
import shutil
import compileall
def package(root_path="./test_project/",reserve_one=False):
"""
编译根目录下的包括子目录里的所有py文件成pyc文件到新的文件夹下
如果只保留一份文件,请将需编译的目录备份,因为本程序会清空该源文件夹
:param root_path: 需编译的目录
:param reserve_one: 是否只保留一个目录
:return:
"""
root = Path(root_path)
# 先删除根目录下的pyc文件和__pycache__文件夹
for src_file in root.rglob("*.pyc"):
os.remove(src_file)
for src_file in root.rglob("__pycache__"):
os.rmdir(src_file)
current_day = datetime.date.today() # 当前日期
edition = "1.0" # 设置版本号
dest = Path(root.parent / f"{root.name}_{edition}.{'001'}_beta_{current_day}") # 目标文件夹名称
if os.path.exists(dest):
shutil.rmtree(dest)
shutil.copytree(root, dest)
compileall.compile_dir(root, force=True) # 将项目下的py都编译成pyc文件
for src_file in root.glob("**/*.pyc"): # 遍历所有pyc文件
relative_path = src_file.relative_to(root) # pyc文件对应模块文件夹名称
dest_folder = dest / str(relative_path.parent.parent) # 在目标文件夹下创建同名模块文件夹
os.makedirs(dest_folder, exist_ok=True)
dest_file = dest_folder / (src_file.stem.rsplit(".", 1)[0] + src_file.suffix) # 创建同名文件
print(f"install {relative_path}")
shutil.copyfile(src_file, dest_file) # 将pyc文件复制到同名文件
# 清除源py文件
for src_file in dest.rglob("*.py"):
os.remove(src_file)
# 清除源目录文件
if reserve_one:
if os.path.exists(root):
shutil.rmtree(root)
dest.rename(root)
if __name__ == '__main__':
package(root_path="./test_project/",reserve_one=False)
# 会清空源文件夹,记得备份,适合上线部署,删除源代码,防止泄露
# package(root_path="./test_project/",reserve_one=True)
补充相关pyc文件
原来Python的程序中,是把原始程序代码放在.py文件里,而Python会在执行.py文件的时候。将.py形式的程序编译成中间式文件(byte-compiled)的.pyc文件,这么做的目的就是为了加快下次执行文件的速度。
所以,在我们运行python文件的时候,就会自动首先查看是否具有.pyc文件,如果有的话,而且.py文件的修改时间和.pyc的修改时间一样,就会读取.pyc文件,否则,Python就会读原来的.py文件。
其实并不是所有的.py文件在与运行的时候都会产生.pyc文件,只有在import相应的.py文件的时候,才会生成相应的.pyc文件