【问题标题】:Structuring python projects without path hacks在没有路径黑客的情况下构建 python 项目
【发布时间】:2017-08-16 10:01:28
【问题描述】:

我有一个在多个项目中使用的共享 python 库,所以结构如下所示:

Project1
    main.py <--- (One of the projects that uses the library)
...
sharedlib
    __init__.py
    ps_lib.py
    another.py

现在在每个项目的 main.py 中,我使用以下 hack 使其工作:

import os
import sys
sys.path.insert(0, os.path.abspath('..'))

import sharedlib.ps_lib
...

有没有办法在不使用这个 hack 的情况下做到这一点?或者有没有更好的方法来组织项目结构?

【问题讨论】:

  • 为什么不直接“安装”sharedlib 作为包?然后你可以在任何地方导入它。
  • @Rahul 我不喜欢这种方法,因为它不优雅,而且在项目的每个模块中你都会有“from .. import ...”
  • @MSeifert 但是在共享库中的每个小修复之后,我将不得不再次 pip 安装它
  • 不一定,您可以安装类似python setup.py develop 的“符号链接”。这样,如果您更改sharedlib,更改将立即生效(或者如果您使用交互式解释器,则在解释器重新启动后)。
  • @MSeifert 这是个好主意!符号链接可以在 Windows 中使用吗?

标签: python python-import directory-structure organization project-structure


【解决方案1】:

我认为最好的方法是让sharedlib 成为一个真正的包。这意味着稍微改变结构:

sharedlib/
    sharedlib/
        __init__.py
        ps_lib.py
        another.py
    setup.py

setup.py 中使用类似的东西(部分取自Python-packaging "Minimal Structure"):

from setuptools import setup

setup(name='sharedlib',
      version='0.1',
      description='...',
      license='...',
      packages=['sharedlib'],   # you might need to change this if you have subfolders.
      zip_safe=False)

然后在sharedlib 包的根文件夹中使用python setup.py developpip install -e . 安装它。

这样(使用develop-e 选项)对sharedlib/sharedlib/* 文件内容的更改将可见,而无需重新安装sharedlib 包 - 尽管如果您可能需要重新启动解释器在交互式解释器中重新工作。那是因为解释器缓存了已经导入的包。

来自setuptools 文档:

Setuptools 允许您部署项目以在公共目录或暂存区域中使用,但无需复制任何文件。 因此,您可以在其签出目录中编辑每个项目的代码,并且只需要在更改项目的 C 扩展名或类似编译的文件时运行构建命令。 [...]

为此,请使用setup.py develop 命令。

(强调我的)

最重要的是您现在可以在任何地方使用import sharedlib - 不再需要在PATHPYTHONPATH 中插入sharedlib 包,因为现在是Python(或者至少是您安装它的Python)像对待任何其他已安装的软件包一样对待 sharedlib

【讨论】:

    【解决方案2】:

    post 描述了一种组织项目的好方法 在我看来,如果是共享库,您必须考虑将其用作真正的库(包含在 virtualenv 中)或为每个项目添加一个文件夹“lib”。

    【讨论】:

    • 是的,这是我看的第一个地方,但他们也使用这个 hack:“sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname (文件), '..')))"
    • 就我个人而言,我不喜欢这种做法,因为如果你想打包你的所有应用程序,你就会有另一个目录的依赖关系,而它并没有真正被引用。我会优先将它添加到每个应用程序的 lib 文件夹中。我选择的主要原因是有人从 repo 下载代码的情况下,他将无法执行应用程序,因为此引用不在下载的项目中
    【解决方案3】:

    我们这样做的方式是为 python 脚本使用 bash 入口脚本。我们的目录结构类似于以下内容:

    /opt/stackoverflow/
                     -> bin
                     -> conf
                     -> lib
                     -> log
    

    然后我们的 lib 文件夹包含我们所有的子项目

    /opt/stackoverflow/lib/
                        -> python_algorithms
                        -> python_data_structures
                        -> python_shared_libraries
    

    然后当我们要执行python脚本时,我们将通过bin目录中的bash脚本执行它

    /opt/stackoverflow/bin/
                        -> quick_sort.sh
                        -> merge_sort.sh
    

    如果我们 cat 我们的入口脚本之一

    cat merge_sort.sh
    
    #!/bin/bash
    export STACKOVERFLOW_HOME=/opt/stackoverflow
    export STACKOVERFLOW_BIN=${STACKOVERFLOW_HOME}/bin
    export STACKOVERFLOW_LIB=${STACKOVERFLOW_HOME}/lib
    export STACKOVERFLOW_LOG=${STACKOVERFLOW_HOME}/log
    export STACKOVERFLOW_CONF=${STACKOVERFLOW_HOME}/conf
    
    # Do any pre-script server work here
    
    export PYTHONPATH=${PYTHONPATH}:${STACKOVERFLOW_LIB}
    
    /usr/bin/python "${STACKOVERFLOW_LIB}/python_algorithms/merge_sort.py" $* 2>&1
    

    【讨论】:

    • 这不会导致您的PYTHONPATH 增长吗?每次运行此 bash 脚本时,都会附加路径 ${STACKOVERFLOW_LIB}(无论它是否已经是路径的一部分)。
    • 假设您使用 1 个用户进行所有操作并且不注销服务器,它将继续增长。
    猜你喜欢
    • 2010-10-04
    • 2014-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-11
    • 2016-12-06
    • 2023-03-16
    • 2023-03-09
    相关资源
    最近更新 更多