我花了几天的时间才能在Mac OS Lion上运行一个科学的Python环境。我尝试了SciPack Superpack路由,还尝试了通过pip和easy_install进行的各种手动安装,但是尝试导入或使用各种模块时仍然出现错误。根据this Stackoverflow thread中的建议,我使用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,则它将出现在sys.path中,在/ Library条目之后但在/ opt条目之前。因此它不能解决问题。
如果我使用-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__,我已经确认它是在导入本地软件包,而不是外来软件包。
但是,我认为这是一种解决方法/做法,而不是真正的解决方案。一个解决方案应使其表现出预期的效果,即:从/ opt / local / ...安装启动的Macports Python,应将通过Macports安装的软件包优先放在/ opt / local / ...目录树中,然后转到其他位置仅当模块在本地不存在时。因此,例如,我希望/ opt / local条目在sys.path中排在首位,而/ Library条目在列表中排在后面。
看来这应该是默认行为,我在Stackoverflow上看到了很多评论,它们只是断言这是Macports Python的行为方式。所以...我怎么做到的?
最佳答案
您遇到的问题至少有两个单独的根本原因。一种是Python 2.7的非系统OS X框架版本(包括MacPorts Python 2.7)故意在site-packages
中通常在该实例所属的/Library/Python/2.7/site-packages
末尾包含系统Python sys.path
位置sys.path
。 site-packages
目录。这在上游Python中一直是一个有争议的功能,MacPorts尚有一个开放的问题来删除它(https://trac.macports.org/ticket/34763),理由是最好将系统Python和MacPorts Python完全分开。
第二个根本原因是OS X随附的原始setuptools
软件包及其easy_install
命令的行为。您已经发现,它通过对sys.path
文件的一些魔术来对.pth
进行了一些精美的操作,包括easy-install.pth
,以确保使用easy_install
安装的软件包首先出现在sys.path
中,并覆盖这些软件包的其他已安装版本。就像您已经发现的那样,删除该行为的一种方法(也是最简单的方法)是删除easy-install.pth
中的/Library/Python/2.7/site-packages
文件。假设您不想使用Apple提供的系统Python那里安装的任何软件包。
将来避免此问题的长期策略是确保您不要使用在easy_install
中找到的Apple提供的easy_install-2.7
或/usr/bin
命令。他们会将软件包安装到/Library/Python
供系统Python使用,并将创建或更新easy-install.pth
。通常,应避免同时使用easy_install
。它的现代替代品是pip
,可提供更好的控制并避免使用.pth
文件的技巧。如果MacPorts尚未为要安装的Python软件包提供端口,通常为py27-xxxx
形式,请安装并使用MacPorts py27-pip
端口而不是easy_install
:
/opt/local/bin/pip-2.7 install xxxx
您还可以使用通常的MacPorts功能,例如
port select pip pip27
。