【问题标题】:Start Another Program From Python >Separately<从 Python 启动另一个程序>单独<
【发布时间】:2012-10-25 22:08:16
【问题描述】:

我正在尝试从 Python 运行一个外部的、独立的程序。通常这不会是一个问题,但该程序是一个游戏,并且内置了一个 Python 解释器。当我使用 subprocess.Popen 时,它会启动单独的程序,但会在原始程序的 Python 实例下这样做,以便它们共享第一个 Python 控制台。我可以很好地结束第一个程序,但我宁愿有单独的控制台(主要是因为我已经隐藏了控制台启动,但是当我使用 subprocess.POpen 从 Python 启动程序时它会显示出来)。

如果我可以完全独立地启动第二个程序,我希望它就像我只是“双击它”一样。此外,os.system 将无法工作,因为我的目标是跨平台兼容性,并且仅在 Windows 上可用。

【问题讨论】:

标签: python subprocess


【解决方案1】:

如果我可以完全独立地启动第二个程序,我会很高兴,就好像我只是“双击它”一样。

从 2.7 和 3.3 开始,Python 没有跨平台的方式来执行此操作。将来可能会添加新的shutil.open 方法(可能不在该名称下);有关详细信息,请参阅http://bugs.python.org/issue3177。但在那之前,您必须为您关心的每个平台编写自己的代码。

幸运的是,与 shutil.open 最终希望提供的相比,您尝试做的事情更简单,更不通用,这意味着编码并不难:

  • 在 OS X 上,有一个名为 open 的命令完全符合您的要求:“打开命令打开文件(或目录或 URL),就像您双击文件的图标一样。”所以,你可以popenopen /Applications/MyGame.app
  • 在 Windows 上,等效命令是 start,但不幸的是,它是 cmd.exe shell 的一部分,而不是独立程序。幸运的是,Python 附带了一个函数 os.startfile,它可以做同样的事情,所以只需 os.startfile(r'C:\Program Files\MyGame\MyGame.exe')
  • 在与 FreeDesktop 兼容的 *nix 系统(包括大多数现代 linux 发行版等)上,有一个非常相似的命令,称为 xdg-open:“xdg-open 在用户首选应用程序中打开文件或 URL。”同样,只需popenxdg-open /usr/local/bin/mygame
  • 如果您希望在其他平台上运行,则需要进行一些研究以找到最佳的等价物。否则,对于 Mac 和 Windows 以外的任何东西,我都会尝试 popen xdg-open,如果失败则抛出错误。

请参阅http://pastebin.com/XVp46f7X 了解(未经测试的)示例。

请注意,这仅适用于运行实际上可以双击以在 Finder/Explorer/Nautilus/etc 中启动的内容。例如,如果您尝试启动“./script.py”,根据您的设置,它可能会启动一个包含您的脚本的文本编辑器。

此外,在 OS X 上,您希望运行 .app 包,而不是其中的 UNIX 可执行文件。 (在某些情况下,启动一个 UNIX 可执行文件——无论是在 .app 包中还是独立的——可能会起作用,但不要指望它。)

另外,请记住,以这种方式启动程序与从命令行运行程序不同 - 特别是,它将从 Windows/Launch Services/GNOME 继承其环境、当前目录/驱动器等/KDE/等。会话,而不是来自您的终端会话。如果您需要对子进程进行更多控制,则需要查看 openxdg-openos.startfile 的文档和/或提出不同的解决方案。

最后,仅仅因为open/xdg-open/os.startfile成功并不意味着游戏正常启动。例如,如果它在创建窗口之前启动然后崩溃,那么在您看来它仍然是成功的。

您可能想在 PyPI 中寻找可以满足您需求的库。 http://pypi.python.org/pypi/desktop 看起来很有可能。

或者您可以查看 issue 3177 中的补丁,然后选择您最喜欢的补丁。据我所知,它们都是纯 Python,您可以轻松地将添加的函数放到您自己的模块中,而不是 osshutil

作为一个快速破解,您可以(ab)使用webbrowser.open。 “请注意,在某些平台上,尝试使用此功能打开文件名可能会工作并启动操作系统的关联程序。但是,这既不支持也不可移植。”特别是 IIRC,它不适用于 OS X 10.5+。但是,我相信从文件名中创建一个 file: URL 实际上确实适用于 OS X 和 Windows,并且对于大多数(但不是全部)配置也适用于 linux。如果是这样,它对于快速和肮脏的脚本可能已经足够了。请记住,它没有被记录在案,它可能会为您的某些用户破坏,它可能会在将来破坏,并且它被 Python 开发人员明确认为是滥用,所以我不会指望它更严重。启动 'script.py' 或 'Foo.app/Contents/MacOS/foo'、传递 env 变量等也会遇到与上述更正确的方法相同的问题。

您问题中的几乎所有其他内容都是不相关且错误的:

通常不会有问题,但程序是游戏,并且内置了 Python 解释器。

没关系。如果游戏从 C 代码写入标准输出,它会做同样的事情。

当我使用 subprocess.Popen 时,它会启动单独的程序,但在原始程序的 Python 实例下这样做

不,它没有。它启动了一个全新的进程,其嵌入式 Python 解释器是一个全新的 Python 实例。您可以通过例如运行与游戏嵌入不同的 Python 版本来验证这一点。

以便他们共享第一个 Python 控制台。

不,他们没有。它们可能共享同一个 tty/cmd 窗口,但这不是一回事。

我可以很好地结束第一个程序,但我宁愿有单独的控制台(主要是因为我隐藏了控制台启动,但是当我使用 subprocess.POpen 从 Python 启动程序时它会显示)。

您始终可以通过管道将子进程的 stdout 和 stderr 传输到例如日志文件,然后您可以根据需要从父进程的输出中单独查看该日志文件。但我认为这与你真正关心的事情无关。

此外,os.system 将无法工作,因为我的目标是跨平台兼容性,而这仅适用于 Windows。

错了; os.system 在“Unix, Windows”上可用——这可能是你关心的任何地方。但是,它不起作用,因为它使用相同的 tty 在脚本的子 shell 中运行子程序。 (而且它还有很多其他问题——例如,阻塞直到孩子完成。)

【讨论】:

  • webbrowser 模块似乎可以自动拾取 xdg-open, open, startfile()。虽然不清楚如何使用它们来运行 python 脚本,例如 xdg-open script.py 打开一个编辑器,而 shell 中的 ./script.py 运行它。
  • 好点。我不认为./script.py 案例在这里是相关的,因为 OP 明确地试图打开一个游戏,就像他双击它一样,但它仍然值得一提。此外,webbrowser.open 绝对是一个 hack,但值得讨论。所以,我已经更新了答案。
  • 感谢您提供的信息,所有这些东西都值得一试。奇怪的是,没有跨平台的方式来简单地启动另一个单独的程序。我猜我必须为每个操作系统使用特殊情况。无论如何,非常感谢!
  • 好吧,如果您阅读 issue 3177 中的 cmets,您可以了解为什么它尚未实施。很难设计出比最小公分母更灵活的东西,也很难很好地处理错误等等。看起来我们最终会得到一些东西,但除非你不打算在 Python 3.4 或 3.5 之前发布你的代码,现在对你没有帮助……
【解决方案2】:

当我使用 subprocess.Popen 时,它会启动单独的程序,但在原始程序的 Python 实例下这样做...

不正确。

...以便他们共享第一个 Python 控制台。

是你问题的症结所在。如果您希望它在另一个控制台中运行,那么您必须运行 another 控制台并告诉 it 改为运行您的程序。

...我的目标是跨平台兼容性...

抱歉,没有跨平台的方法可以做到这一点。您需要运行适合该平台的控制台/终端。

【讨论】:

  • 真的吗?这很奇怪,因为我正在运行的游戏是在 Python 附带的引擎中制作的(它不是用 Python 编写的),所以运行游戏会运行 Python 控制台的一个实例。如果我运行两个游戏实例,每个实例都有自己独立的 Python 控制台。有没有办法只调用一个单独的程序来运行?
  • 这都是正确的,但这是一个有点绝望和令人沮丧的答案。在 OP 可能关心的所有平台上执行此操作并不难,而且您绝对不想通过找到正确的终端程序并运行它来做到这一点。 (一方面,在 *nix 平台上,这甚至不需要打开一个新的终端窗口。)
猜你喜欢
  • 2018-05-17
  • 2014-11-05
  • 1970-01-01
  • 2012-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多