我对此问题提出了类似的问题:Similar Question。 我有一个GUI,用户可以输入信息,其他脚本使用其中一些信息来运行。每个按钮有4个不同的脚本。我将它们作为一个子进程运行,以便主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文件中,我添加了:
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'] ...我无法让它工作。有任何想法吗?我不确定它是否给了我这个错误,因为它是一个子进程。
答案 0 :(得分:1)
假设您无法重新构建您的应用,因此这不是必需的(例如,使用multiprocessing
代替subprocess
),有三种解决方案:
pkg_resources
- 并将脚本复制到临时目录,以便您可以从那里运行。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!
您可能希望在现实生活中考虑一些变化:
__import__(sys.argv[1][2:]).run(sys.argv[2:])
之类的内容进行适当的错误处理。argparse
代替这个hacky特殊大小写作为第一个参数。如果您已经向脚本发送了非平凡的参数,那么您可能已经在使用argparse
或替代方案。if __name__ == '__main__':
的脚本添加run(sys.argv[1:])
块,这样在开发过程中您仍然可以直接运行脚本来测试它们。我没有做任何这些,因为他们模糊了这个琐碎的例子的想法。
1如果您已经完成了文档,那么文档很有用,但作为教程和解释性原理,并非如此。并且试图编写那些辉煌的PyPA人员多年来无法想出的教程......这可能超出了SO答案的范围。