我花了几天的时间努力在 Mac OS Lion 上运行一个科学的 Python 环境。我尝试了 SciPack Superpack 路线,以及通过 pip 和 easy_install 进行的各种手动安装,但在尝试导入或使用各种模块时仍然出错。根据此 Stackoverflow 线程中的建议,我使用 MacPorts 设置了全新安装。
但是,当我运行 macports Python 时,它会忽略 macports 安装中的包,而是尝试从旧安装中加载不兼容的包。我绝对确定我正在运行新安装的 macports Python。我检查了符号链接并检查了 python_select 并通过直接输入新安装的路径来启动 Python。但是当我尝试导入 statsmodels 时,它会从另一个目录中提取旧版本。
以下是 sys.path 的内容(为简洁而编辑):
['',
'/Library/Python/2.7/site-packages/mrjob-0.4.3_dev-py2.7.egg',
'/Library/Python/2.7/site-packages/statsmodels-0.6.0-py2.7-macosx-10.9-intel.egg',
...
'/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python',
'/Library/Python/2.7/site-packages/twilio-3.6.6-py2.7.egg',
'/Library/Python/2.7/site-packages/six-1.6.1-py2.7.egg',
'/Library/Python/2.7/site-packages/httplib2-0.9-py2.7.egg',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/readline',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/PyObjC',
'/Library/Python/2.7/site-packages']
macports 安装在 /opt/local 下,而旧版安装在 /Library/Python 下。如您所见,较旧的软件包在列表中较高,这意味着它们具有较高的优先级。
环境变量 PYTHONPATH 为空。如果我确实将任何内容放入 PYTHONPATH,它会出现在 /Library 条目之后但 /opt 条目之前的 sys.path 中。所以它不能解决问题。
如果我使用 -S 选项调用新的 python,则 sys.path 变为:
['',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python27.zip',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-darwin',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/plat-mac/lib-scriptpackages',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-tk',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-old',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/lib-dynload']
这成功地摆脱了外星站点包条目,但它也破坏了 macports 的站点包条目,所以我无法加载任何东西。
我认为罪魁祸首是一个名为 /Library/Python/2.7/site-packages/easy-install.pth 的文件,其内容如下(为简洁起见再次编辑):
import sys; sys.__plen = len(sys.path)
./mrjob-0.4.3_dev-py2.7.egg
...
./statsmodels-0.6.0-py2.7-macosx-10.9-intel.egg
...
/System/Library/Frameworks/Python.framework/Versions/2.7/Extras/lib/python
./twilio-3.6.6-py2.7.egg
./six-1.6.1-py2.7.egg
./httplib2-0.9-py2.7.egg
import sys; new=sys.path[sys.__plen:]; del sys.path[sys.__plen:]; p=getattr(sys,'__egginsert',0); sys.path[p:p]=new; sys.__egginsert = p+len(new)
如果我在启动 macports python 之前重命名该文件,python 不再将这些外来包添加到它的 sys.path 中。现在 sys.path 看起来很像我使用“python -S”选项时的样子,除了它最后有这些额外的条目:
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages',
'/opt/local/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/PyObjC',
'/Library/Python/2.7/site-packages'
现在我可以加载 macports 自己的包,例如 statsmodels。通过检查 statsmodels.__file__ 我已经确认它正在导入本地包而不是外来包。
但是,我认为这是一种解决方法/kludge,而不是真正的解决方案。一个解决方案应该让它按预期运行,即:Macports 的 Python,从 /opt/local/... 安装启动,应该优先考虑通过 macports 安装的包到 /opt/local/... 目录树中,然后去其他地方寻找仅当模块在本地不存在时。因此,例如,我希望 /opt/local 条目在 sys.path 中排在第一位,而 /Library 条目则在列表的下方。
看起来这应该是默认行为,我在 Stackoverflow 上看到了很多评论,只是断言这就是 Macports Python 的行为方式。那么……我该怎么做呢?