Python包的本地集合:导入它们的最佳方式?

时间:2013-02-22 14:40:35

标签: python module package local software-distribution

我需要提供一个使用存储在本地Library目录中的多个的Python程序的集合:目标是避免让用户安装包在使用我的程序之前(包在Library目录中提供)。导入Library中包含的软件包的最佳方法是什么?

我尝试了三种方法,但没有一种方法看起来很完美:是否有更简单,更健壮的方法?或者是最好的方法之一?

  1. 在第一种方法中,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添加相同路径的副本,这是一种浪费。此外,所有程序必须包含相同的三条路径修改行,这违背了“不要重复自己”的原则。

  2. 对上述问题的改进包括尝试仅在导入的模块中添加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程序。

  3. 来自Library的Python 模块也可以通过将其作为一个包(存储在其中的空__init__.py文件)导入,这允许人们做:

    from Library import module_from_Library
    

    但是,这会打破Library中的,因为它们可能会执行类似from xlutils.filter import …的操作,因为xlutils中找不到sys.path }}。因此,此方法有效,但仅限于Library中的模块,而不是包。

  4. 所有这些方法都有一些缺点。

    是否有更好的方法可以使用存储在本地Library目录中的一组软件包(他们使用的)来运送程序?或者是上述方法之一(方法1?)最好的方法之一?

    PS :就我而言,Library中的所有软件包都是纯Python软件包,但最适用于任何操作系统的更通用的解决方案是最好的。

    PPS :目标是用户无需安装任何内容即可使用我的程序(除了复制我定期发送的目录之外),如上例所示。

    PPPS :更准确地说,我们的目标是能够轻松更新我的程序集合及其相关的第三方软件包Library让我的用户执行包含我的程序和“隐藏”第三方软件包的Library文件夹的目录的简单副本。 (我经常更新,所以我不想强迫用户更新他们的Python发行版。)

2 个答案:

答案 0 :(得分:2)

sys.path()混在一起导致痛苦...... modern package templateDistribute包含大量信息,并且部分设置用于解决您的问题。

我要做的是设置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下的源代码。