Запуск другой программы из Python> Отдельно <

Я пытаюсь запустить внешнюю, отдельную программу из Python. Это не будет проблемой нормально, но программа - игра, и в нее встроен интерпретатор Python. Когда я использую subprocess.Popen, он запускает отдельную программу, но делает это под исходной программой Python, так что они совместно используют первую консоль Python. Я могу закончить первую программу отлично, но я бы предпочел иметь отдельные консоли (в основном потому, что я запускаю консоль, но она отображается, когда я запускаю программу из Python с помощью subprocess.POpen).

Мне бы хотелось, если бы я мог запустить вторую программу полностью самостоятельно, как будто я просто "дважды щелкнул по ней". Кроме того, os.system не будет работать, потому что я нацелен на кросс-платформенную совместимость и доступен только в Windows.

Ответ 1

Мне бы хотелось, если бы я мог запустить вторую программу полностью самостоятельно, как будто я просто "дважды щелкнул по ней".

Начиная с 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, а не отдельная программа. К счастью, у 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", в зависимости от ваших настроек он может просто запустить текстовый редактор с вашим script в нем.

Кроме того, в OS X вы хотите запустить пакет .app, а не исполняемый файл UNIX внутри него. (В некоторых случаях запуск исполняемого файла UNIX, будь то внутри пакета .app или автономный, может работать, но не рассчитывать на него.)

Кроме того, имейте в виду, что запуск программы таким образом - это не то же самое, что запускать ее из командной строки - в частности, она наследует ее среду, текущий каталог/диск и т.д. из Windows/Launch Services/GNOME/KDE/и т.д.. а не сеанса терминала. Если вам нужно больше контролировать дочерний процесс, вам нужно будет посмотреть документацию для open, xdg-open и os.startfile и/или придумать другое решение.

Наконец, только потому, что open/xdg-open/os.startfile преуспевает, на самом деле не означает, что игра началась правильно. Например, если он запускается, а затем падает до того, как он даже может создать окно, он все равно будет для вас удачным.

Вы можете посмотреть вокруг PyPI для библиотек, которые делают то, что вы хотите. http://pypi.python.org/pypi/desktop выглядит как возможность.

Или вы можете просмотреть исправления в выпуске 3177 и выбрать тот, который вам больше нравится. Насколько я знаю, они все чистые Python, и вы можете просто просто добавить добавленную функцию в свой собственный модуль, а не в os или shutil.

Как быстрый хак, вы можете (ab) использовать webbrowser.open. "Обратите внимание, что на некоторых платформах, пытаясь открыть имя файла, используя эту функцию, может работать и запускать связанную с операционной системой программу. Однако это не поддерживается и не переносится". В частности, IIRC, он не будет работать на OS X 10.5+. Тем не менее, я считаю, что создание файла: URL-адрес из имени файла действительно работает на OS X и Windows, а также работает на linux для большинства, но не для всех конфигураций. Если это так, это может быть достаточно хорошим для быстрого и грязного script. Просто имейте в виду, что он не документирован для работы, он может сломаться для некоторых ваших пользователей, он может сломаться в будущем, и он явно рассмотрел злоупотребления со стороны разработчиков Python, поэтому я не стал бы рассчитывать на это для чего-то более серьезного. И он будет иметь те же проблемы с запуском 'script.py' или 'Foo.app/Contents/MacOS/foo', передавая переменные env и т.д. В качестве более правильного метода выше.

Почти все остальное в вашем вопросе не имеет значения и неправильное:

Это не будет проблемой нормально, но программа - игра, и в нее встроен интерпретатор Python.

Это не имеет значения. Если игра пишут на stdout из кода C, она будет делать то же самое.

Когда я использую subprocess.Popen, он запускает отдельную программу, но делает это в рамках оригинальной программы Python instance

Нет, нет. Он запускает совершенно новый процесс, встроенный интерпретатор Python - это совершенно новый экземпляр Python. Вы можете проверить это, например, запустив другую версию Python, чем игра.

чтобы они делили первую консоль Python.

Нет, они этого не делают. Они могут иметь одно и то же окно tty/cmd, но это не то же самое.

Я могу закончить первую программу отлично, но я бы предпочел иметь отдельные консоли (в основном из-за того, что консоль запускается скрытой, но она отображается, когда я запускаю программу из Python с помощью subprocess.POpen).

Вы всегда можете подключить дочерний stdout и stderr к, например, файлу журнала, который вы могли бы затем просмотреть отдельно от вывода родительского процесса, если хотите. Но я думаю, что это происходит по касательной, которая не имеет никакого отношения к тому, что вам действительно нужно.

Кроме того, os.system не будет работать, потому что я нацелен на кросс-платформенную совместимость и доступен только в Windows.

Неправильный; os.system доступен в "Unix, Windows" - это, вероятно, везде, о чем вы заботитесь. Однако это не сработает, потому что он запускает дочернюю программу в подоболочке вашего script, используя ту же самую tty. (И у него появилось много других проблем - например, блокировка, пока ребенок не закончит.)

Ответ 2

Когда я использую subprocess.Popen, он запускает отдельную программу, но делает это в исходной программе Python экземпляра...

Неправильно.

... чтобы они делили первую консоль Python.

В этом суть вашей проблемы. Если вы хотите, чтобы он запускался в другой консоли, вы должны запустить другую консоль и сказать ей, чтобы она запускала вашу программу.

... Я нацелен на кросс-платформенную совместимость...

Извините, нет кросс-платформенного способа сделать это. Вам нужно будет запустить консоль/терминал, подходящий для платформы.