从 Python 启动另一个程序>单独<
问题描述
我正在尝试从 Python 运行一个外部的、独立的程序.通常这不会是一个问题,但该程序是一个游戏,并且内置了一个 Python 解释器.当我使用 subprocess.Popen 时,它会启动单独的程序,但会在原始程序的 Python 实例下这样做,以便它们共享第一个 Python 控制台.我可以很好地结束第一个程序,但我宁愿有单独的控制台(主要是因为我已经隐藏了控制台启动,但是当我使用 subprocess.POpen 从 Python 启动程序时它会显示出来).
I'm trying to run an external, separate program from Python. It wouldn't be a problem normally, but the program is a game, and has a Python interpreter built into it. When I use subprocess.Popen, it starts the separate program, but does so under the original program's Python instance, so that they share the first Python console. I can end the first program fine, but I would rather have separate consoles (mainly because I have the console start off hidden, but it gets shown when I start the program from Python with subprocess.POpen).
如果我可以完全独立地启动第二个程序,我会很高兴,就好像我只是双击它"一样.此外,os.system 将无法工作,因为我的目标是跨平台兼容性,并且仅在 Windows 上可用.
I would like it if I could start the second program wholly on its own, as though I just 'double-clicked on it'. Also, os.system won't work because I'm aiming for cross-platform compatibility, and that's only available on Windows.
解决方案
如果我可以完全独立地启动第二个程序,我会很高兴,就好像我只是双击它"一样.
I would like it if I could start the second program wholly on its own, as though I just 'double-clicked on it'.
从 2.7 和 3.3 开始,Python 没有跨平台的方式来执行此操作.将来可能会添加一个新的 shutil.open
方法(可能不在该名称下);有关详细信息,请参阅 http://bugs.python.org/issue3177.但在那之前,您必须为您关心的每个平台编写自己的代码.
As of 2.7 and 3.3, Python doesn't have a cross-platform way to do this. A new shutil.open
method may be added in the future (possibly not under that name); see http://bugs.python.org/issue3177 for details. But until then, you'll have to write your own code for each platform you care about.
幸运的是,与 shutil.open
最终希望提供的相比,您尝试做的事情更简单,更不通用,这意味着编码并不难:
Fortunately, what you're trying to do is simpler and less general than what shutil.open
is ultimately hoped to provide, which means it's not that hard to code:
- 在 OS X 上,有一个名为
open
完全符合您的要求:open 命令打开文件(或目录或 URL),就像您双击文件的图标一样."所以,你可以popen
open/Applications/MyGame.app
. - 在 Windows 上,等效命令是
start
,但不幸的是,它是cmd.exe
shell 的一部分,而不是独立程序.幸运的是,Python 自带了一个函数os.startfile
做同样的事情,所以只需os.startfile(r'C:Program FilesMyGameMyGame.exe')
. - 在与 FreeDesktop 兼容的 *nix 系统(包括大多数现代 linux 发行版等)上,有一个非常相似的命令,称为
xdg-open
: "xdg-open 在用户的首选应用程序中打开文件或 URL."同样,只需popen
xdg-open/usr/local/bin/mygame
. - 如果您希望在其他平台上运行,则需要进行一些研究以找到最佳的等价物.否则,对于 Mac 和 Windows 以外的任何东西,我都会尝试
popen
xdg-open
,如果失败则抛出错误.
- On OS X, there's a command called
open
that does exactly what you want: "The open command opens a file (or a directory or URL), just as if you had double-clicked the file's icon." So, you can justpopen
open /Applications/MyGame.app
. - On Windows, the equivalent command is
start
, but unfortunately, that's part of thecmd.exe
shell rather than a standalone program. Fortunately, Python comes with a functionos.startfile
that does the same thing, so justos.startfile(r'C:Program FilesMyGameMyGame.exe')
. - On FreeDesktop-compatible *nix systems (which includes most modern linux distros, etc.), there's a very similar command called
xdg-open
: "xdg-open opens a file or URL in the user's preferred application." Again, justpopen
xdg-open /usr/local/bin/mygame
. - If you expect to run on other platforms, you'll need to do a bit of research to find the best equivalent. Otherwise, for anything besides Mac and Windows, I'd just try to
popen
xdg-open
, and throw an error if that fails.
有关(未经测试的)示例,请参阅 http://pastebin.com/XVp46f7X.
See http://pastebin.com/XVp46f7X for an (untested) example.
请注意,这仅适用于运行实际上可以双击以在 Finder/Explorer/Nautilus/etc 中启动的内容.例如,如果您尝试启动./script.py",根据您的设置,它可能会启动一个包含您的脚本的文本编辑器.
Note that this will only work to run something that actually can be double-clicked to launch in Finder/Explorer/Nautilus/etc. For example, if you try to launch './script.py', depending on your settings, it may just fire up a text editor with your script in it.
此外,在 OS X 上,您希望运行 .app 包,而不是其中的 UNIX 可执行文件.(在某些情况下,启动一个 UNIX 可执行文件——无论是在 .app 包中还是独立的——可能会起作用,但不要指望它.)
Also, on OS X, you want to run the .app bundle, not the UNIX executable inside it. (In some cases, launching a UNIX executable—whether inside an .app bundle or standalone—may work, but don't count on it.)
另外,请记住,以这种方式启动程序与从命令行运行程序不同 - 特别是,它将从 Windows/Launch Services/GNOME 继承其环境、当前目录/驱动器等/KDE/等.会话,而不是来自您的终端会话.如果您需要对子进程进行更多控制,则需要查看 open
、xdg-open
和 os.startfile
的文档和/或提出不同的解决方案.
Also, keep in mind that launching a program this way is not the same as running it from the command line—in particular, it will inherit its environment, current directory/drive, etc. from the Windows/Launch Services/GNOME/KDE/etc. session, not from your terminal session. If you need more control over the child process, you will need to look at the documentation for open
, xdg-open
, and os.startfile
and/or come up with a different solution.
最后,仅仅因为 open
/xdg-open
/os.startfile
成功并不意味着游戏正常启动.例如,如果它在创建窗口之前启动然后崩溃,那么在您看来它仍然是成功的.
Finally, just because open
/xdg-open
/os.startfile
succeeds doesn't actually mean that the game started up properly. For example, if it launches and then crashes before it can even create a window, it'll still look like success to you.
您可能想在 PyPI 中寻找可以满足您需求的库.http://pypi.python.org/pypi/desktop 看起来很有可能.
You may want to look around PyPI for libraries that do what you want. http://pypi.python.org/pypi/desktop looks like a possibility.
或者您可以查看 issue 3177 中的补丁,然后选择您最喜欢的补丁.据我所知,它们都是纯 Python,您可以轻松地将添加的函数放到您自己的模块中,而不是放在 os
或 shutil
中.
Or you could look through the patches in issue 3177, and pick the one you like best. As far as I know, they're all pure Python, and you can easily just drop the added function in your own module instead of in os
or shutil
.
作为一个快速破解,您可以(ab)使用 webbrowser.open
.请注意,在某些平台上,尝试使用此功能打开文件名可能会工作并启动操作系统的相关程序.但是,这既不支持也不可移植."特别是 IIRC,它不适用于 OS X 10.5+.但是,我相信从文件名中创建一个 file: URL 实际上确实适用于 OS X 和 Windows,并且对于大多数(但不是全部)配置也适用于 linux.如果是这样,它对于快速而肮脏的脚本可能就足够了.请记住,它没有被记录在案,它可能会为您的某些用户破坏,它可能会在将来破坏,并且它被 Python 开发人员明确认为是滥用,所以我不会指望它更严重.启动 'script.py' 或 'Foo.app/Contents/MacOS/foo'、传递 env 变量等与上述更正确的方法相同.
As a quick hack, you may be able to (ab)use webbrowser.open
. "Note that on some platforms, trying to open a filename using this function, may work and start the operating system’s associated program. However, this is neither supported nor portable." In particular, IIRC, it will not work on OS X 10.5+. However, I believe that making a file: URL out of the filename actually does work on OS X and Windows, and also works on linux for most, but not all, configurations. If so, it may be good enough for a quick&dirty script. Just keep in mind that it's not documented to work, it may break for some of your users, it may break in the future, and it's explicitly considered abuse by the Python developers, so I wouldn't count on it for anything more serious. And it will have the same problems launching 'script.py' or 'Foo.app/Contents/MacOS/foo', passing env variables, etc. as the more correct method above.
您问题中的几乎所有其他内容都是不相关且错误的:
Almost everything else in your question is both irrelevant and wrong:
通常不会有问题,但程序是游戏,并且内置了 Python 解释器.
It wouldn't be a problem normally, but the program is a game, and has a Python interpreter built into it.
没关系.如果游戏从 C 代码写入标准输出,它会做同样的事情.
That doesn't matter. If the game were writing to stdout from C code, it would do the exact same thing.
当我使用 subprocess.Popen 时,它会启动单独的程序,但在原始程序的 Python 实例下这样做
When I use subprocess.Popen, it starts the separate program, but does so under the original program's Python instance
不,它没有.它启动了一个全新的进程,其嵌入式 Python 解释器是一个全新的 Python 实例.您可以通过例如运行与游戏嵌入不同的 Python 版本来验证这一点.
No it doesn't. It starts an entirely new process, whose embedded Python interpreter is an entirely new instance of Python. You can verify that by, e.g., running a different version of Python than the game embeds.
以便他们共享第一个 Python 控制台.
so that they share the first Python console.
不,他们没有.它们可能共享同一个 tty/cmd 窗口,但这不是一回事.
No they don't. They may share the same tty/cmd window, but that's not the same thing.
我可以很好地结束第一个程序,但我宁愿有单独的控制台(主要是因为我隐藏了控制台启动,但是当我使用 subprocess.POpen 从 Python 启动程序时它会显示出来).
I can end the first program fine, but I would rather have separate consoles (mainly because I have the console start off hidden, but it gets shown when I start the program from Python with subprocess.POpen).
您始终可以将子进程的 stdout 和 stderr 通过管道传输到例如日志文件,如果您愿意,您可以将其与父进程的输出分开查看.但我认为这与你真正关心的事情无关.
You could always pipe the child's stdout and stderr to, e.g., a logfile, which you could then view separately from the parent process's output, if you wanted to. But I think this is going off on a tangent that has nothing to do with what you actually care about.
此外,os.system 将无法工作,因为我的目标是跨平台兼容性,而这仅适用于 Windows.
Also, os.system won't work because I'm aiming for cross-platform compatibility, and that's only available on Windows.
错了;os.system
在Unix, Windows"——这可能无处不在.但是,它不起作用,因为它使用相同的 tty 在脚本的子 shell 中运行子程序.(而且它还有很多其他问题——例如,阻塞直到孩子完成.)
Wrong; os.system
is available on "Unix, Windows"--which is probably everywhere you care about. However, it won't work because it runs the child program in a subshell of your script, using the same tty. (And it's got lots of other problems—e.g., blocking until the child finishes.)
相关文章