本文目录导读:
我来为你提供几个实用的Python编译脚本案例,从简单到复杂逐步展示。
基础编译脚本(编译单个.py文件)
# compile_single.py
import py_compile
import sys
import os
def compile_python_file(source_file):
"""
编译单个Python文件到字节码
"""
if not os.path.exists(source_file):
print(f"错误:文件 {source_file} 不存在")
return False
try:
# 编译并生成.pyc文件
compiled_file = py_compile.compile(source_file, cfile=source_file + 'c')
print(f"✅ 编译成功:{source_file}")
print(f" 生成文件:{compiled_file}")
return True
except py_compile.PyCompileError as e:
print(f"❌ 编译失败:{e}")
return False
if __name__ == "__main__":
if len(sys.argv) < 2:
print("用法:python compile_single.py <filename.py>")
sys.exit(1)
source = sys.argv[1]
compile_python_file(source)
批量编译脚本(编译整个项目)
# compile_project.py
import compileall
import os
import sys
from pathlib import Path
def compile_project(project_path, force=False, quiet=False):
"""
批量编译整个Python项目
参数:
- project_path: 项目根目录
- force: 是否强制重新编译
- quiet: 是否静默模式
"""
project_path = Path(project_path)
if not project_path.exists():
print(f"错误:目录 {project_path} 不存在")
return False
print(f"开始编译项目:{project_path}")
print(f"强制重新编译:{'是' if force else '否'}")
print("-" * 50)
# 使用compileall批量编译
success = compileall.compile_dir(
str(project_path),
force=force,
quiet=quiet,
rx=re.compile(r'/.git/|/__pycache__/') # 排除git和缓存目录
)
if success:
print("-" * 50)
print("✅ 项目编译完成!")
else:
print("-" * 50)
print("❌ 编译过程中存在错误")
return success
if __name__ == "__main__":
import re
# 示例用法
project_dir = "." if len(sys.argv) < 2 else sys.argv[1]
compile_project(
project_dir,
force=True, # 强制重新编译
quiet=False # 显示详细信息
)
编译并打包为可执行文件(使用PyInstaller)
# compile_and_package.py
import subprocess
import sys
import os
import shutil
from pathlib import Path
def build_executable(script_path,
name=None,
one_file=True,
windowed=False,
icon_path=None,
extra_data=None):
"""
使用PyInstaller将Python脚本编译为可执行文件
参数:
- script_path: Python脚本路径
- name: 输出文件名
- one_file: 是否生成单个文件
- windowed: 是否隐藏控制台窗口
- icon_path: 图标文件路径
- extra_data: 额外数据文件列表
"""
# 检查PyInstaller是否安装
try:
import PyInstaller
except ImportError:
print("❌ 请先安装PyInstaller:pip install pyinstaller")
return False
# 构建命令
cmd = ["pyinstaller"]
if one_file:
cmd.append("--onefile") # 单文件模式
if windowed:
cmd.append("--windowed") # 无控制台窗口
if name:
cmd.extend(["--name", name])
if icon_path:
cmd.extend(["--icon", icon_path])
# 添加额外数据文件
if extra_data:
for src, dst in extra_data:
cmd.extend(["--add-data", f"{src}:{dst}"])
cmd.append(script_path)
print("开始构建可执行文件...")
print(f"执行命令:{' '.join(cmd)}")
print("-" * 50)
try:
# 执行PyInstaller
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode == 0:
print("✅ 构建成功!")
print(f"输出位置:{Path.cwd() / 'dist'}")
# 显示生成的文件
dist_dir = Path.cwd() / "dist"
if dist_dir.exists():
for f in dist_dir.iterdir():
print(f" - {f.name}")
else:
print("❌ 构建失败!")
print("错误信息:")
print(result.stderr)
except Exception as e:
print(f"❌ 发生异常:{e}")
return False
return True
if __name__ == "__main__":
# 示例用法
if len(sys.argv) < 2:
print("用法:python compile_and_package.py <script.py> [options]")
sys.exit(1)
build_executable(
script_path=sys.argv[1],
name="MyApp", # 输出文件名
one_file=True, # 单文件
windowed=False, # 显示控制台
icon_path=None, # 自定义图标
extra_data=[ # 附加资源文件
("config.json", "."),
("assets/", "assets")
]
)
完整的编译与优化脚本
# advanced_compile.py
import py_compile
import compileall
import dis
import marshal
import struct
import time
import os
import sys
from pathlib import Path
from datetime import datetime
class PythonCompiler:
"""Python编译与优化工具"""
def __init__(self, source_dir, optimize_level=2):
self.source_dir = Path(source_dir)
self.optimize_level = optimize_level
self.stats = {
'total': 0,
'success': 0,
'failed': 0,
'skipped': 0
}
def compile_with_optimization(self, file_path):
"""
编译单个文件并应用优化
优化级别:
0 - 基础编译
1 - 移除断言
2 - 移除断言和docstring
"""
file_path = Path(file_path)
if not file_path.exists() or not file_path.suffix == '.py':
return False
try:
# 读取源代码
with open(file_path, 'r', encoding='utf-8') as f:
source = f.read()
# 编译代码(带优化)
code = compile(
source,
str(file_path),
'exec',
optimize=self.optimize_level
)
# 生成.pyc文件路径
cache_dir = file_path.parent / '__pycache__'
cache_dir.mkdir(exist_ok=True)
pyc_file = cache_dir / f"{file_path.stem}.cpython-{sys.version_info.minor}.pyc"
# 写入编译后的字节码
with open(pyc_file, 'wb') as f:
# 写入魔数和时间戳
f.write(importlib.util.MAGIC_NUMBER)
f.write(struct.pack('<I', int(time.time())))
f.write(b'\0' * 4) # 源文件大小(可选)
# 写入序列化的代码对象
marshal.dump(code, f)
# 显示优化信息
if self.optimize_level > 0:
original_size = len(source)
compiled_size = os.path.getsize(pyc_file)
print(f" 优化级别:{self.optimize_level}")
print(f" 源文件大小:{original_size} 字节")
print(f" 编译后大小:{compiled_size} 字节")
return True
except SyntaxError as e:
print(f" 语法错误:{e}")
return False
except Exception as e:
print(f" 编译错误:{e}")
return False
def analyze_bytecode(self, file_path):
"""分析字节码"""
import importlib.util
try:
# 加载编译后的模块
spec = importlib.util.spec_from_file_location("temp_module", file_path)
module = importlib.util.module_from_spec(spec)
# 反汇编函数的字节码
print(f"\n📊 字节码分析:{file_path}")
print("-" * 40)
for name in dir(module):
obj = getattr(module, name)
if callable(obj) and not name.startswith('_'):
print(f"\n函数:{name}")
dis.dis(obj)
except Exception as e:
print(f"分析失败:{e}")
def compile_all(self, recursive=True):
"""编译所有Python文件"""
pattern = "**/*.py" if recursive else "*.py"
print(f"🔧 Python编译工具 - 优化级别 {self.optimize_level}")
print(f"📂 源目录:{self.source_dir}")
print(f"⏰ 开始时间:{datetime.now().strftime('%H:%M:%S')}")
print("=" * 50)
# 收集所有Python文件
py_files = list(self.source_dir.glob(pattern))
print(f"📄 找到 {len(py_files)} 个Python文件\n")
# 编译每个文件
for py_file in py_files:
self.stats['total'] += 1
# 跳过__init__.py和缓存文件
if py_file.name == '__init__.py' or '__pycache__' in str(py_file):
self.stats['skipped'] += 1
continue
print(f"编译:{py_file.relative_to(self.source_dir)}")
if self.compile_with_optimization(py_file):
self.stats['success'] += 1
print(" ✅ 成功")
else:
self.stats['failed'] += 1
print(" ❌ 失败")
# 显示统计信息
print("\n" + "=" * 50)
print("📊 编译统计:")
print(f" 总文件数:{self.stats['total']}")
print(f" 编译成功:{self.stats['success']}")
print(f" 编译失败:{self.stats['failed']}")
print(f" 跳过文件:{self.stats['skipped']}")
print(f" 成功率:{self.stats['success']/max(self.stats['total'],1)*100:.1f}%")
if __name__ == "__main__":
import importlib
# 使用示例
compiler = PythonCompiler(
source_dir=".", # 当前目录
optimize_level=2 # 最高优化级别
)
# 编译所有文件
compiler.compile_all(recursive=True)
# 分析特定文件的字节码
# compiler.analyze_bytecode("your_module.py")
自动化构建脚本
# build_system.py
import os
import sys
import json
import subprocess
from pathlib import Path
from datetime import datetime
class BuildSystem:
"""自动化构建系统"""
def __init__(self, config_file="build_config.json"):
self.config = self.load_config(config_file)
self.start_time = None
self.build_id = datetime.now().strftime("%Y%m%d_%H%M%S")
def load_config(self, config_file):
"""加载构建配置"""
default_config = {
"name": "MyPythonProject",
"version": "1.0.0",
"entry_point": "main.py",
"output_dir": "dist",
"compile_options": {
"optimize": 2,
"bytes": True,
"strip_comments": True,
"include_packages": ["requests", "numpy"],
"exclude_patterns": ["*test*", "*example*"]
},
"build_steps": [
"clean",
"compile",
"package",
"test"
],
"post_build": {
"archive": True,
"sign": False,
"deploy": False
}
}
try:
with open(config_file, 'r') as f:
config = json.load(f)
return {**default_config, **config}
except FileNotFoundError:
print(f"未找到配置文件,使用默认配置")
return default_config
def clean(self):
"""清理构建目录"""
print("\n🧹 清理构建目录...")
dirs_to_clean = [
"__pycache__",
self.config['output_dir'],
"build"
]
for dir_name in dirs_to_clean:
path = Path(dir_name)
if path.exists():
import shutil
shutil.rmtree(path)
print(f" 删除:{dir_name}")
def compile(self):
"""编译所有Python文件"""
print("\n🔨 编译Python文件...")
from compileall import compile_dir
# 创建输出目录
output_dir = Path(self.config['output_dir'])
output_dir.mkdir(exist_ok=True)
# 编译设置
compile_options = self.config['compile_options']
# 使用compileall编译
compile_dir(
".",
force=True,
quiet=0,
rx=compile_options.get('exclude_patterns', [])
)
print("✅ 编译完成")
def package(self):
"""打包项目"""
print("\n📦 打包项目...")
import zipfile
output_dir = Path(self.config['output_dir'])
output_file = output_dir / f"{self.config['name']}_{self.config['version']}.zip"
with zipfile.ZipFile(output_file, 'w', zipfile.ZIP_DEFLATED) as zf:
# 添加Python文件
for py_file in Path('.').rglob('*.py'):
if '__pycache__' not in str(py_file):
zf.write(py_file)
# 添加配置文件
if Path('config.json').exists():
zf.write('config.json')
print(f"✅ 打包完成:{output_file}")
def run_tests(self):
"""运行测试"""
print("\n🧪 运行测试...")
import pytest
test_files = list(Path('.').rglob('test_*.py'))
if test_files:
result = pytest.main(["-v"])
if result == 0:
print("✅ 所有测试通过")
else:
print("❌ 测试失败")
return False
else:
print("⚠️ 未找到测试文件")
return True
def build(self):
"""执行完整构建流程"""
print(f"\n{'='*50}")
print(f"🏗️ 开始构建:{self.config['name']} v{self.config['version']}")
print(f" 构建ID:{self.build_id}")
print(f"{'='*50}")
self.start_time = datetime.now()
# 按步骤执行构建
for step in self.config['build_steps']:
print(f"\n📌 步骤:{step}")
if step == "clean":
self.clean()
elif step == "compile":
self.compile()
elif step == "package":
self.package()
elif step == "test":
if not self.run_tests():
print("❌ 构建失败:测试未通过")
return False
# 构建完成
elapsed = (datetime.now() - self.start_time).seconds
print(f"\n{'='*50}")
print(f"✅ 构建完成!")
print(f" 耗时:{elapsed} 秒")
print(f" 输出位置:{Path(self.config['output_dir']).absolute()}")
print(f"{'='*50}")
return True
if __name__ == "__main__":
# 创建构建系统实例
builder = BuildSystem("build_config.json")
# 执行完整构建
builder.build()
使用示例
基础编译
# 编译单个文件 python compile_single.py my_script.py # 批量编译项目 python compile_project.py /path/to/project
编译为可执行文件
# 需要先安装PyInstaller pip install pyinstaller # 打包为单文件 python compile_and_package.py my_app.py --onefile # 打包为单个可执行文件,带图标 python compile_and_package.py my_app.py --name MyApp --icon app.ico
高级编译优化
# 使用优化级别2编译 python advanced_compile.py
自动化构建
# 创建配置文件
echo '{
"name": "MyApp",
"version": "1.0.0",
"entry_point": "main.py"
}' > build_config.json
# 执行构建
python build_system.py
这些脚本覆盖了Python编译的常见场景,从简单的单文件编译到完整的自动化构建系统,你可以根据实际需求选择使用或修改这些脚本。
标签: Python编译