gpt4 book ai didi

python - 如何使用pyinstaller将多个子进程python文件编译成单个.exe文件

转载 作者:太空宇宙 更新时间:2023-11-04 04:45:06 24 4
gpt4 key购买 nike

我有一个类似的问题:Similar Question .我有一个 GUI,用户可以在其中输入信息,其他脚本使用其中的一些信息来运行。每个按钮有 4 个不同的脚本。我将它们作为子进程运行,这样主图形用户界面就不会运行或说它没有响应。这是我所拥有的示例,因为自从我使用 PAGE 生成 gui 以来,代码真的很长。

###Main.py#####
import subprocess

def resource_path(relative_path):
#I got this from another post to include images but I'm also using it to include the scripts"
try:
# PyInstaller creates a temp folder and stores path in _MEIPASS
base_path = sys._MEIPASS
except Exception:
base_path = os.path.abspath(".")

return os.path.join(base_path, relative_path)
Class aclass:
def get_info(self):
global ModelNumber, Serial,SpecFile,dateprint,Oper,outputfolder
ModelNumber=self.Model.get()
Serial=self.SerialNumber.get()
outputfolder=self.TEntry2.get()
SpecFile= self.Spec_File.get()

return ModelNumber,Serial,SpecFile,outputfolder

def First(self):
aclass.get_info(self) #Where I use the resource path function
First_proc = subprocess.Popen([sys.executable, resource_path('first.py'),str(ModelNumber),str(Serial),str(path),str(outputfolder)])
First_proc.wait()


#####First.py#####
import numpy as np
import scipy
from main import aclass

ModelNumber = sys.argv[1]
Serial = sys.argv[2]
path = sys.argv[3]
path_save = sys.argv[4]

我的第二个、第三个和第四个脚本都是如此。

在我的规范文件中,我添加了:

a.datas +=[('first.py','C\\path\\to\\script\\first.py','DATA')]
a.datas +=[('main.py','C\\path\\to\\script\\main.py','DATA')]

这可以编译并且可以工作,但是当我尝试将它转换为 .exe 时,它​​会崩溃,因为它无法正确导入 first.py 及其自己的库(numpy、scipy...等)。我已经尝试将它添加到规范文件中的 a.datas 和 runtime_hooks=['first.py'] ......但我无法让它工作。有任何想法吗?我不确定它是否给我这个错误,因为它是一个子进程。

最佳答案

假设您无法重组您的应用程序,因此这不是必需的(例如,通过使用 multiprocessing 而不是 subprocess),有以下三种解决方案:

  • 确保 .exe 包含作为(可执行)zip 文件的脚本——或者只使用 pkg_resources——并将脚本复制到一个临时目录,以便您可以从那里运行它。
  • 编写一个多入口点包装器脚本,它可以作为您的主程序运行,也可以作为每个脚本运行——因为,虽然您不能从打包的 exe 中运行脚本,但您可以从中导入一个模块
  • 再次使用 pkg_resources,编写一个包装器来运行脚本,方法是将脚本作为字符串加载并改为使用 exec 运行。

第二个可能是最干净的,但它有点工作。而且,虽然我们可以依赖 setuptools entrypoints对于某些工作,尝试解释如何执行此操作比解释如何手动执行要困难得多,1 所以我将执行后者。


假设您的代码如下所示:

# main.py
import subprocess
import sys
spam, eggs = sys.argv[1], sys.argv[2]
subprocess.run([sys.executable, 'vikings.py', spam])
subprocess.run([sys.executable, 'waitress.py', spam, eggs])

# vikings.py
import sys
print(' '.join(['spam'] * int(sys.argv[1])))

# waitress.py
import sys
import time
spam, eggs = int(sys.argv[1]), int(sys.argv[2]))
if eggs > spam:
print("You can't have more eggs than spam!")
sys.exit(2)
print("Frying...")
time.sleep(2)
raise Exception("This sketch is getting too silly!")

所以,你像这样运行它:

$ python3 main.py 3 4
spam spam spam
You can't have more eggs than spam!

我们想重新组织它,以便有一个脚本查看命令行参数来决定要导入的内容。这是做到这一点的最小变化:

# main.py
import subprocess
import sys
if sys.argv[1][:2] == '--':
script = sys.argv[1][2:]
if script == 'vikings':
import vikings
vikings.run(*sys.argv[2:])
elif script == 'waitress':
import waitress
waitress.run(*sys.argv[2:])
else:
raise Exception(f'Unknown script {script}')
else:
spam, eggs = sys.argv[1], sys.argv[2]
subprocess.run([sys.executable, __file__, '--vikings', spam])
subprocess.run([sys.executable, __file__, '--waitress', spam, eggs])

# vikings.py
def run(spam):
print(' '.join(['spam'] * int(spam)))

# waitress.py
import sys
import time
def run(spam, eggs):
spam, eggs = int(spam), int(eggs)
if eggs > spam:
print("You can't have more eggs than spam!")
sys.exit(2)
print("Frying...")
time.sleep(2)
raise Exception("This sketch is getting too silly!")

现在:

$ python3 main.py 3 4
spam spam spam
You can't have more eggs than spam!

在现实生活中您可能需要考虑的一些变化:

  • DRY:我们为每个脚本复制并粘贴了相同的三行代码,我们必须将每个脚本名称键入三次。您可以使用 __import__(sys.argv[1][2:]).run(sys.argv[2:]) 之类的东西进行适当的错误处理。
  • 对第一个参数使用argparse 而不是这种怪异的特殊外壳。如果您已经向脚本发送了重要的参数,那么您可能已经在使用 argparse 或其他替代方法。
  • 为每个只调用 run(sys.argv[1:]) 的脚本添加一个 if __name__ == '__main__': block ,以便在开发过程中您仍然可以直接运行脚本来测试它们。

我没有做任何这些,因为它们会掩盖这个微不足道的例子的想法。


1 如果您已经阅读过该文档,那么该文档非常适合作为复习资料,但作为教程和解释性基本原理,就不那么重要了。并尝试编写优秀的 PyPA 人员多年来未能提出的教程……这可能超出了 SO 答案的范围。

关于python - 如何使用pyinstaller将多个子进程python文件编译成单个.exe文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49806594/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com