我希望我可以完全地启动第二个程序,就像我刚双击它一样。截至Python 2.7和3.3,Python 没有跨平台的方法来实现这一点。未来可能会添加新的shutil.open 方法(可能不是以这个名字),请参见
http://bugs.python.org/issue3177了解详情。但在那之前,您需要为每个关心的平台编写自己的代码。
幸运的是,你想做的事情比shutil.open 最终希望提供的更简单、更少一般性,这意味着编码并不那么困难:
- 在 OS X 上,有一个名为
open
的命令可以实现你想要的功能:“open 命令打开一个文件(或目录或 URL),就像你双击文件图标一样。”因此,你只需 popen
open /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。”同样地,只需 popen
xdg-open /usr/local/bin/mygame
。
- 如果你期望在其他平台上运行,你需要进行一些研究,找到最佳的替代方案。否则,在 Mac 和 Windows 以外的任何情况下,我会尝试
popen
xdg-open
,如果失败就抛出错误。
请参考http://pastebin.com/XVp46f7X(未经测试)的示例。
请注意,这只适用于可以双击在Finder/Explorer/Nautilus等中启动的程序。例如,如果您尝试启动'./script.py',根据您的设置,它可能只会在文本编辑器中打开脚本。
此外,在OS X上,您需要运行.app包而不是其中的UNIX可执行文件。(在某些情况下,启动UNIX可执行文件——无论是在.app包内还是独立运行——都可能有效,但不要指望它。)
同时,请记住,以这种方式启动程序与从命令行运行程序不同——特别是,它将继承其环境、当前目录/驱动器等信息,而不是从终端会话中继承。如果您需要更多控制子进程,则需要查看open
、xdg-open
和os.startfile
的文档和/或想出不同的解决方案。
最后,仅仅因为open
/xdg-open
/os.startfile
执行成功,并不意味着游戏已经启动成功。例如,如果它在创建窗口之前启动并崩溃,你仍然会认为它是成功的。
您可以在PyPI上寻找符合您需求的库。http://pypi.python.org/pypi/desktop看起来是一个可能的选择。
或者您可以查看问题3177中的补丁,并选择您最喜欢的补丁。据我所知,它们都是纯Python编写的,您可以轻松地将添加的函数放入自己的模块中,而不是放在os
或shutil
中。
作为一个快速的hack,你或许可以(滥用)
webbrowser.open
。"请注意,在某些平台上,尝试使用此函数打开文件名可能会启动操作系统关联的程序。然而,这既不被支持也不是可移植的。" 特别地,如果我没记错的话,它在OS X 10.5+上不起作用。然而,我认为将文件名制作成file: URL实际上在OS X和Windows上都有效,并且对于大多数但不是全部配置的Linux也有效。如果是这样,它或许足够用于一个快速脚本。只需记住它没有被记录为有效,可能会对一些用户造成问题,可能会在未来出现问题,它被Python开发人员明确地视为滥用,所以我不会指望它用于更严肃的事情。并且,与上述更正确的方法一样,它也会有启动'script.py'或'Foo.app/Contents/MacOS/foo'、传递环境变量等相同的问题。
你提到的几乎所有其他内容都是不相关和错误的:
通常情况下这不是问题,但该程序是一个游戏,并且内置了Python解释器。如果游戏是从C代码写入stdout,它也会做同样的事情。
当我使用subprocess.Popen时,它会启动一个单独的程序,但是在原始程序的Python实例下执行。
不会的。它会启动一个全新的进程,其嵌入式Python解释器是全新的Python实例。例如,您可以通过运行与游戏嵌入版本不同的Python版本来验证这一点。
它们不会共享第一个Python控制台。它们可能共享相同的tty/cmd窗口,但这不是同一回事。
我可以很好地结束第一个程序,但我更愿意拥有单独的控制台(主要是因为我让控制台初始处于隐藏状态,但是当我使用subprocess.POpen从Python启动程序时,它会显示)。
你可以将子进程的标准输出和错误输出导入到一个日志文件中,这样你就可以从父进程的输出中单独查看它们。但我认为这与你实际关心的内容无关。
此外,os.system不起作用,因为我想实现跨平台兼容性,而这只在Windows上可用。
错了;os.system
可以在“Unix、Windows”上使用——这可能是你关心的所有平台。然而,它不起作用,因为它在脚本的子shell中运行子程序,使用相同的tty。(还有很多其他问题,例如阻塞直到子进程完成。)