如何仅在.pyc缺失或过期时编译.py脚本并执行?
问题解答
一、仅在必要时编译.py为.pyc
默认情况下,py_compile.compile()的force参数为False,它会自动检查目标.pyc文件是否存在,以及对应的.py文件修改时间是否晚于.pyc。如果.pyc已存在且未过时,就不会重新编译。你之前每次都重新编译,大概率是手动设置了force=True,去掉该参数或设为False即可实现按需编译。
如果需要更精细的手动控制,也可以直接对比文件修改时间:
import os import py_compile def compile_if_needed(py_path): # 仅在.pyc缺失或过时的时候编译 py_compile.compile(py_path, force=False) # 用法示例 compile_if_needed("Child1.py")
另外,Python的import机制本身就内置了这个逻辑:导入模块时,若对应的.pyc不存在或比.py旧,解释器会自动编译生成.pyc。如果只是想确保模块编译后再执行,直接导入模块是更简洁的方式。
二、exec()能否运行.pyc文件
exec()可以运行.pyc文件中的字节码,但需要先正确读取并解析.pyc内容。.pyc文件开头包含魔法数、时间戳等头部信息,不能直接将整个文件内容传给exec(),需要跳过这些头部(Python 3.7+通常是前16字节,不同版本可能略有差异),提取字节码后再执行。
示例代码:
import marshal def exec_pyc(pyc_path): with open(pyc_path, "rb") as f: # 跳过头部信息 f.read(16) bytecode = marshal.load(f) exec(bytecode) # 用法示例,注意.pyc路径在__pycache__目录下,文件名含Python版本标识 exec_pyc("__pycache__/Child1.cpython-310.pyc")
结合示例实现完整需求
假设Parent.py需要管理Child1.py的编译与执行,完整代码如下:
Parent.py
import os import sys import py_compile import marshal def get_pyc_path(py_path): # 生成对应.pyc的路径(适配Python 3的__pycache__结构) dir_name, file_name = os.path.split(py_path) name, ext = os.path.splitext(file_name) pyc_name = f"{name}.cpython-{''.join(map(str, sys.version_info[:2]))}.pyc" return os.path.join(dir_name, "__pycache__", pyc_name) def compile_if_needed(py_path): py_compile.compile(py_path, force=False) def exec_pyc(pyc_path): with open(pyc_path, "rb") as f: f.read(16) bytecode = marshal.load(f) exec(bytecode) def compile_and_exec(py_path): compile_if_needed(py_path) pyc_path = get_pyc_path(py_path) exec_pyc(pyc_path) if __name__ == "__main__": compile_and_exec("Child1.py")
Child1.py(示例内容)
print("Child1模块执行中...")
运行Parent.py时,只会在Child1.pyc缺失或过时的情况下重新编译,随后执行.pyc文件内容。
内容的提问来源于stack exchange,提问作者NickC
相关产品推荐
相关产品推荐

