代码之家  ›  专栏  ›  技术社区  ›  deptstoremook

项目结构导致冗余点符号

  •  3
  • deptstoremook  · 技术社区  · 7 年前

    我创建了一个Python包,它构建在Kenneth Reitz的“Repository structure and Python”中指出的结构上( 1 ). 主程序包路径为:

    /projects-folder (not site-packages)
        /package
            /package
                __init__.py
                Datasets.py
                Draw.py
                Gmaps.py
                ShapeSVG.py
                project.py
            __init__.py
            setup.py
    

    对于当前结构,我必须使用以下模块导入语法:

    import package.package.Datasets
    

    我希望键入以下内容:

    import package.Datasets
    

    当然,我可以两次键入同一个单词,但从更深的意义上讲,我感觉是错误的,也就是说,我的包结构不正确,或者误解了Python对该结构的解释。

    外部 __init__.py 是Python检测此包所必需的,根据文档( 2 ). 但这就建立了 /package/ 作为包的顶层,以及 /package/package/ 作为一个子包,我不得不使用上面笨拙的导入语法。

    为了避免这种情况,我的选择似乎是:

    • 创建一个包,其中外部文件夹包含顶级包模块。
    • 将内部文件夹添加到我的 PYTHONPATH 环境变量。

    然而,这两种方法似乎都不是最理想的解决办法,因为它们本来就不应该成为问题。我该怎么办?

    2 回复  |  直到 7 年前
        1
  •  3
  •   user2357112    7 年前

    你误解了。你有两个 package 出于某种原因,你引用的消息来源从未说过要这么做。外部文件夹,带有 setup.py ,不应该是一个包。

    听起来您正在运行Python projects-folder 并试图从那里导入您的包。这不是你应该做的。您有几个选项可以将包导入导入系统。(我将使用 设置。py公司 在it中作为 setupfolder ,以将其与内部文件夹区分开来):

    • 使用构建包 设置。py公司 例如 python setup.py bdist-wheel --universal ,并使用pip安装构建的软件包。
    • 跳过构建步骤,只需运行 pip install path/to/setupfolder . 如果您想分发包,构建包会生成一个有用的安装程序,但可能您不想这样做。
    • 在开发模式下使用“安装”包的源代码树 pip install -e path/to/setupfolder ,因此Python导入系统将在执行导入时定位包的源树。这很方便,因为如果编辑源存储库,您不必重新构建和重新安装,尽管您仍然希望重新启动使用该包的任何正在运行的Python进程。
    • 直接从内部运行Python setupfolder设置文件夹 .

    这些选项中的任何一个都将导致您的包可以作为 包裹 而不是 package.package ,这是应该的。

        2
  •  1
  •   Mad Physicist    7 年前

    虽然我不完全同意您的包结构,但您可以利用 __all__ 到目前为止,我所看到的可能是star进口产品的合法用途。 __init__.py 除了将文件夹标识为包或子包之外,它还有更多用途。

    使用星形导入

    在里面 package/package/__init__.py ,添加变量 __全部__ 声明要导出的所有公共元素:

    __all__ = ['Datasets', 'Draw', 'Gmaps', 'ShapeSVG', 'project']
    

    在里面 package/__init__.py from package.package import * . 现在所有可用的属性 package.package.x 还将提供 package.x .

    如果要直接复制 package.package.__all__ package.__all__ (这是可选的,但允许您执行以下操作 from package import * 正确),您可以执行以下操作

    from package.package import *
    from package.package import __all__ as _all
    __all__ = _all
    del _all
    

    不使用星形导入

    不用使用 包裹包装__全部__ 完全只需添加 __全部__ 直接发送至 包/\uu init\uuuu。py公司 和使用 from package.package import x -样式导入:

    from package.package import (
        Datasets, Draw, Gmaps, ShapeSVG, project
    )
    # As before, package.__all__ is optional
    __all__ = ['Datasets', 'Gmaps', 'ShapeSVG', 'project']
    

    我还是建议你 包裹包装__全部__ 变量,但对于此特定用途,它是可选的。

    利弊

    这两种方法都非常合理,我在重大项目中看到了这两种方法的使用。第一种方法减少了冗余。只能在一个位置定义公共导出: 包裹包装__全部__ . The star导入和 包装__全部__ 直接引用该定义,引出一个您真正需要维护的地方。另一方面,有时需要将“完整”分隔开 包裹包裹x个 通过以下方式公开的API 包裹x个 给临时用户。在这种情况下,选择第二个选项。唯一的缺点是你必须更加小心 包装__全部__ 并且相应的导入正确同步。

    笔记

    我看到的许多项目(尤其想到numpy)都使用这种技术将各个模块的属性导出到顶层。例如,如果您有一个函数 package.package.Datasets.get_data ,它将列在 package.package.Datasets.__all__ ,将导入到 pacakge.package.__init__ ,附加到 包裹包装__全部__ ,然后被顶级包引用,并且 包装__全部__ .