【问题标题】:Automatically call common initialization code without creating __init__.py file自动调用常用初始化代码,无需创建 __init__.py 文件
【发布时间】:2011-11-07 05:10:31
【问题描述】:

我的项目中有两个目录:

project/
  src/
  scripts/

"src" 包含我完善的代码,"scripts" 包含一次性 Python 脚本。

我希望所有脚本都将“../src”添加到它们的 sys.path 中,以便它们可以访问“src”树下的模块。一种方法是编写一个 scripts/__init__.py 文件,其内容为:

scripts/__init__.py:
  import sys
  sys.path.append("../src")

这可行,但有将我的所有脚本放在一个名为“脚本”的包中的不良副作用。还有其他方法可以让我的所有脚本自动调用上述初始化代码吗?

我可以在我的 .bashrc 中编辑 PYTHONPATH 环境变量,但我希望我的脚本能够开箱即用,而不需要用户摆弄 PYTHONPATH。另外,我不喜欢仅仅为了适应这个项目而对整个帐户进行更改。

【问题讨论】:

  • 你能解释一下“一次性”是什么意思吗?这些脚本是要在安装您的应用后向最终用户公开,还是仅用于开发/测试的便利工具?
  • “这可行,但有将我所有的脚本放在一个名为“脚本”的模块中的副作用。你能解释为什么这是一个问题吗?您可以通过破解__init__.py 来避免命名空间效应,但看起来您正在与语言作斗争(这很糟糕:-))
  • @Simon:看起来你有答案了。想说明我需要做什么来“破解 __init__.py”? :)

标签: python scripting python-module pythonpath


【解决方案1】:

即使您有其他分发计划,也值得在您的src 文件夹中放置一个基本的setup.py。这样,您可以运行 setup.py develop 让 distutils 将您的代码的 链接 放到您的默认路径上(这意味着您所做的任何更改都将在原地反映,而无需“重新安装”,并且所有无论您的脚本在哪里,模块都将“正常工作”)。这将是一次性步骤,但这仍然比零多一步,所以这取决于这是否比更新.bashrc 更麻烦。如果您使用pip,则等效为pip install -e /path/to/src

更强大的解决方案 - 特别是如果您要在多个开发人员的机器上镜像/版本控制这些脚本 - 是在受控的虚拟环境中完成您的开发工作。事实证明 virtualenv 甚至内置了support for making your own bootstrap customizations。似乎您只需要一个 after_install() 挂钩来调整 sitecustomize、运行 pip install -e 或将一个普通的 .pth 文件添加到站点包。自定义引导程序可以与其他脚本一起存在于您的源代码管理中,并且需要为每个开发人员的设置运行一次。您还可以获得使用 virtualenv 的正常好处(显式依赖版本控制、与系统范围的配置隔离以及不同机器之间的标准化等等)。

如果您真的不想进行任何设置步骤并且愿意从“项目”目录中运行这些脚本,那么您可以扑通一声在__init__.py 中:

project/
    src/
        some_module.py
    scripts/
        __init__.py # special "magic"
        some_script.py

这些是您的文件的样子:

# file: project/src/some_module.py
print("importing %r" % __name__)

def some_function():
    print("called some_function() inside %s" % __name__)
--------------------------------------------------------
# file: project/scripts/some_script.py
import some_module

if __name__ == '__main__':
    some_module.some_function()
--------------------------------------------------------
# file: project/scripts/__init__.py
import sys
from os.path import dirname, abspath, join

print("doing magic!")
sys.path.insert(0, join(dirname(dirname(abspath(__file__))), 'src'))

然后你必须像这样运行你的脚本:

[~/project] $ python -m scripts.some_script
doing magic!
importing 'some_module'
called some_function() inside some_module

小心!脚本只能project/内部这样调用:

[~/otherdir] $ python -m scripts.some_script
ImportError: no module named scripts

要启用此功能,您需要返回编辑 .bashrc,或使用上述选项之一。最后的选择应该是最后的手段;正如@Simon 所说,那时你真的在与语言作斗争。

【讨论】:

    【解决方案2】:

    如果您希望脚本可运行(我假设是从命令行运行),它们必须位于某个路径上。

    您尝试做的事情听起来有些奇怪。您能否向我们展示您正在尝试完成的具体示例?

    【讨论】:

      【解决方案3】:

      您可以在项目目录中添加一个名为 'pathHack.py' 的文件,然后将类似这样的内容放入其中:

      import os
      import sys
      pkgDir = os.path.dirname(__file__)
      sys.path.insert(os.path.join(pkgDir, 'scripts')
      

      然后,在项目目录中的 python 文件中,开始:

      import pathHack
      

      现在您可以从脚本目录中导入内容,而无需使用“脚本”。字首。如果你在这个目录下只有一个文件,而且你不关心隐藏这种东西,你可以内联这个sn-p。

      【讨论】:

        猜你喜欢
        • 2012-03-22
        • 2015-11-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-03
        • 2015-09-21
        • 1970-01-01
        相关资源
        最近更新 更多