如何使用pyins将多个子进程python文件编译成一个.exe文件

2024-05-21 00:42:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个类似的问题:Similar Question。 我有一个GUI,用户可以在其中输入信息,其他脚本使用其中的一些信息来运行。我将它们作为子进程运行,这样主gui就不会出现问题或者说它没有响应。这是我所拥有的一个例子,因为我使用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]

我的第二、三、四个剧本都是这样。在

在我的spec文件中,我添加了:

^{pr2}$

这是编译和工作,但当我试图将其转换为.exe时,它会崩溃,因为它无法导入第一.py适当地和它自己的库(numpy,scipy…等等)。我已经尝试将它添加到a.datas中,并且运行时\u hooks=['第一.py']在spec文件中…我不能让它工作。有什么想法吗?我不确定它是否会给我这个错误,因为它是一个子进程。在


Tags: pathpyimportselfbasegetdefsys
1条回答
网友
1楼 · 发布于 2024-05-21 00:42:36

假设你不能重组你的应用程序,所以这是不必要的(例如,通过使用multiprocessing而不是{}),有三种解决方案:

  • 请确保.exe将脚本作为(可执行)zipfile包含,或者只使用pkg_resources-并将脚本复制到一个临时目录中,以便从那里运行它。在
  • 编写一个多入口点包装器脚本,该脚本可以作为主程序运行,也可以作为每个脚本运行,因为虽然不能从压缩的exe运行脚本,但可以从中导入模块。在
  • 再次使用pkg_resources,编写一个运行脚本的包装器,将其作为字符串加载并使用exec运行它。在

第二种可能是最干净的,但它需要做一些工作。而且,虽然我们可以依赖^{} 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!")

所以,你可以这样运行:

^{pr2}$

我们想重新组织它,这样就有一个脚本可以查看命令行参数来决定导入什么。这里有一个最小的改变:

# 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!")

现在:

^{pr2}$

在现实生活中,你可能需要考虑一些改变:

  • DRY:我们为每个脚本复制和粘贴了相同的三行代码,我们必须为每个脚本键入三次名称。您只需使用__import__(sys.argv[1][2:]).run(sys.argv[2:])之类的代码并进行适当的错误处理。在
  • 在第一个参数中使用argparse而不是这个粗糙的特殊大小写。如果您已经在向脚本发送非平凡的参数,那么您可能已经在使用argparse或其他替代方法。在
  • 向每个只调用if __name__ == '__main__':的脚本添加一个if __name__ == '__main__':块,这样在开发期间您仍然可以直接运行脚本来测试它们。在

我没有做这些,因为它们会模糊这个小例子的想法。在


1如果你已经做过了,文档可以作为复习的好东西,但是作为教程和解释性的基本原理,就不那么重要了。并且试图写一篇优秀的PyPA人多年来都没能想出的教程……这可能超出了SO答案的范围。

相关问题 更多 >