我需要提供一个使用存储在本地Library
目录中的多个包的Python程序的集合:目标是避免让用户安装包在使用我的程序之前(包在Library
目录中提供)。导入Library
中包含的软件包的最佳方法是什么?
我尝试了三种方法,但没有一种方法看起来很完美:是否有更简单,更健壮的方法?或者是最好的方法之一?
在第一种方法中,Library
文件夹只是添加到库路径中:
import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'Library'))
import package_from_Library
Library
文件夹放在开头,这样我的程序附带的软件包优先于用户安装的相同模块(这样我确信它们有正确的版本可以使用我的程序)。当Library
文件夹不在当前目录中时,此方法也有效,这很好。但是,这种方法有缺点。我的每个程序都会向sys.path
添加相同路径的副本,这是一种浪费。此外,所有程序必须包含相同的三条路径修改行,这违背了“不要重复自己”的原则。
对上述问题的改进包括尝试仅在导入的模块中添加Library
路径一次:
# In module add_Library_path:
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'Library'))
然后在我的每个程序中使用:
import add_Library_path
import package_from_Library
这样,由于CPython的缓存机制,模块add_Library_path
只运行一次,而Library
路径只添加一次sys.path
。然而,这种方法的一个缺点是import add_Library_path
具有不可见的副作用,并且导入的顺序很重要:这使得代码不易清晰,更脆弱。此外,这也迫使我分发的程序包含一个用户不会使用的add_Library_path.py
程序。
来自Library
的Python 模块也可以通过将其作为一个包(存储在其中的空__init__.py
文件)导入,这允许人们做:
from Library import module_from_Library
但是,这会打破Library
中的包,因为它们可能会执行类似from xlutils.filter import …
的操作,因为xlutils
中找不到sys.path
}}。因此,此方法有效,但仅限于Library
中的模块,而不是包。
所有这些方法都有一些缺点。
是否有更好的方法可以使用存储在本地Library
目录中的一组软件包(他们使用的)来运送程序?或者是上述方法之一(方法1?)最好的方法之一?
PS :就我而言,Library
中的所有软件包都是纯Python软件包,但最适用于任何操作系统的更通用的解决方案是最好的。
PPS :目标是用户无需安装任何内容即可使用我的程序(除了复制我定期发送的目录之外),如上例所示。
PPPS :更准确地说,我们的目标是能够轻松更新我的程序集合及其相关的第三方软件包Library
让我的用户执行包含我的程序和“隐藏”第三方软件包的Library
文件夹的目录的简单副本。 (我经常更新,所以我不想强迫用户更新他们的Python发行版。)
答案 0 :(得分:2)
与sys.path()
混在一起导致痛苦...... modern package template和Distribute包含大量信息,并且部分设置用于解决您的问题。
我要做的是设置setup.py以将所有包安装到特定的站点包位置,或者如果可以将其安装到系统的站点包中。在前一种情况下,本地站点包将被添加到系统/用户的PYTHONPATH。在后一种情况下,没有什么需要改变
您也可以使用批处理文件来设置python路径。或者将python可执行文件更改为指向包含已修改的PYTHONPATH的shell脚本,然后执行python解释器。当然,后者意味着你必须能够访问用户的机器,而你不需要。但是,如果您的用户只运行脚本而不导入您自己的库,那么可以使用您自己的脚本包装器:
#!/path/to/my/python
/path/to/my/python
脚本就像:
#!/bin/sh
PYTHONPATH=/whatever/lib/path:$PYTHONPATH /usr/bin/python $*
答案 1 :(得分:1)
我认为你应该看看path import hooks,它允许在搜索模块时修改python的行为。
例如,你可以尝试做一些类似kde的scriptengine为python插件做的事情[1]。
它为sys.path
添加了一个特殊标记(如"<plasmaXXXXXX>"
,其中XXXXXX
是一个随机数,只是为了避免名称冲突)然后当python尝试导入模块而无法在其他路径,它会调用你的进口商来处理它。
更简单的替代方法是将主脚本用作启动器,只需将路径添加到sys.path
并执行目标文件(这样就可以安全地避免在每个文件上放置sys.path.append(...)
行)
另一个适用于python2.6 +的替代方法是在每用户的site-packages目录下安装库。
[1]你可以在带有kde的linux安装中找到/usr/share/kde4/apps/plasma_scriptengine_python
下的源代码。