Python子进程失败,取决于IDLE的打开方式

1 投票
2 回答
1605 浏览
提问于 2025-04-16 18:20

在一台运行Mac OS X 10.6.7的MacBook Pro上,我有一个简单的Python脚本,叫做'test.py':

import subprocess
subprocess.Popen(['xterm'])

如果我通过鼠标打开IDLE来运行这个脚本,它就会崩溃。但如果我在终端里输入'idle'来启动IDLE,然后运行同样的脚本,它就不会崩溃。这是怎么回事呢?

具体情况:

我通过右键点击test.py,然后选择“用IDLE打开”(版本是2.6.6)来启动IDLE。这样只打开了Python Shell和IDLE,而没有打开test.py。我手动打开test.py,然后从“运行”菜单中选择“运行模块”。下面是Python Shell的内容。最后附上了这种方式打开的IDLE的sys.path。

Python 2.6.6 (r266:84292, May 11 2011, 21:44:06) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "copyright", "credits" or "license()" for more information.

    ****************************************************************
    Personal firewall software may warn about the connection IDLE
    makes to its subprocess using this computer's internal loopback
    interface.  This connection is not visible on any external
    interface and no data is sent to or received from the Internet.
    ****************************************************************

IDLE 2.6.6      
>>> ================================ RESTART ================================
>>> 

Traceback (most recent call last):
  File "/Users/georgepatterson/test.py", line 2, in <module>
    subprocess.Popen(['xterm'])
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 623, in __init__
    errread, errwrite)
  File "/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 1141, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

>>> import sys
>>> for p in sys.path: print p

/Users/georgepatterson
/Users/georgepatterson/Documents
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python26.zip
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/plat-darwin
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/plat-mac
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/plat-mac/lib-scriptpackages
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-tk
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-old
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-dynload
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/PyObjC
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/setuptools-0.6c11-py2.6.egg-info
>>> 

通过终端窗口启动IDLE。打开test.py,然后从“运行”菜单中选择“运行模块”。以这种方式运行时,终端窗口正常打开。我把Python Shell的内容和sys.path也粘贴在下面。

Python 2.6.6 (r266:84292, May 11 2011, 21:44:06) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "copyright", "credits" or "license()" for more information.

    ****************************************************************
    Personal firewall software may warn about the connection IDLE
    makes to its subprocess using this computer's internal loopback
    interface.  This connection is not visible on any external
    interface and no data is sent to or received from the Internet.
    ****************************************************************

IDLE 2.6.6      
>>> ================================ RESTART ================================
>>> 
>>> import sys
>>> for p in sys.path: print p

/Users/georgepatterson
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/bin
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python26.zip
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/plat-darwin
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/plat-mac
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/plat-mac/lib-scriptpackages
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-tk
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-old
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/lib-dynload
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/PyObjC
/opt/local/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/site-packages/setuptools-0.6c11-py2.6.egg-info
>>>

2 个回答

1

sys.path 在这里不太重要(它是用来导入 Python 模块的)。

你应该查看一下 PATH 环境变量:os.environ['PATH']

很可能 OS X 的终端会安装一些额外的路径。

2

你看到的行为差异确实和 PATH 环境变量有关。当你通过终端启动 IDLE 时,它会从你的终端环境中继承 PATH 的值。path_helper(8) 会根据 /etc/paths.d/ 中的条目来设置登录终端的默认 PATH 值。在 OS X 10.6 中,这个值包括 /usr/X11/bin,也就是 xterm 所在的地方。不过,当你从 Finder 启动 IDLE,比如双击 IDLE 应用图标或者用 IDLE 作为默认应用打开文件(就像你在测试 1 中做的那样),就没有使用终端,这时应用环境继承的 PATH 会稍微不同。特别是,/etc/paths.d 不会被查阅,所以 /usr/X11/bin 就不在路径中。你可以通过查看这两种情况下的 PATH 来确认这一点。对于从 Finder 启动的 IDLE.app,你可能会看到类似这样的内容:

>>> os.environ['PATH']
'/usr/bin:/bin:/usr/sbin:/sbin'

虽然可以改变启动进程的默认环境变量,但通常不需要也不推荐这样做。在这种情况下,最简单的解决办法是直接提供 xterm 的绝对路径:

import subprocess
subprocess.Popen(['/usr/X11/bin/xterm'])

或者你也可以自己修改 PATH 来实现更复杂的操作。

撰写回答