8

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

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

4

2 回答 2

7

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

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

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

  • 在 OS X 上,有一个名为的命令open完全符合您的要求:“打开命令打开一个文件(或目录或 URL),就像您双击文件的图标一样。” 所以,你可以popen open /Applications/MyGame.app
  • 在 Windows 上,等效命令是start,但不幸的是,它是 shell 的一部分,cmd.exe而不是独立程序。幸运的是,Python 附带了一个os.startfile做同样事情的函数,所以只需os.startfile(r'C:\Program Files\MyGame\MyGame.exe').
  • 在与 FreeDesktop 兼容的 *nix 系统(包括大多数现代 linux 发行版等)上,有一个非常相似的命令,称为xdg-open:“xdg-open 在用户首选应用程序中打开文件或 URL”。再次,只是popen xdg-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-openos.startfile

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

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

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

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

通常这不会是一个问题,但该程序是一个游戏,并且内置了一个 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 中运行子程序。(而且它还有很多其他问题——例如,阻塞直到孩子完成。)

于 2012-10-25T23:24:20.700 回答
2

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

不正确。

...这样他们就可以共享第一个 Python 控制台。

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

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

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

于 2012-10-25T22:12:54.900 回答