python模块层次结构命名约定

Posted

技术标签:

【中文标题】python模块层次结构命名约定【英文标题】:python modules hierarchy naming convention 【发布时间】:2013-02-20 16:20:18 【问题描述】:

我希望有如下的模块/包结构:

/__init__.py
/mymodule.py
/mymodule/
/mymodule/__init__.py
/mymodule/submodule.py

然后使用如下模块:

import mymodule
import mymodule.submodule

但文件“mymodule.py”似乎与“mymodule”目录冲突。

这里的正确命名约定是什么?

【问题讨论】:

【参考方案1】:

您正在处理一个package。你应该有的包结构是:

/some-parent-directory # This needs to be on sys.path
    /mymodule  # This is not really a module - it's a package
        __init__.py  # import mymodule
        # init is loaded when you `import mymodule` or anything below it
        some.py  # import mymodule.some
        implementation.py  # import mymodule.implementation
        files.py  # import mymodule.files
        /submodule
            __init__.py  # import mymodule.submodule
            # init is loaded when you `import mymodule.submodule` or anything below it
            submodule_impl.py  # import mymodule.submodule.submodule_impl
            goes.py  # import mymodule.submodule.goes
            here.py  # import mymodule.submodule.here

只要 parent 目录位于 sys.path 上,您就可以毫无问题地调用 import mymodulefrom mymodule.submodule import something

如果您想从包的根级别(即from mymodule import SomeItem 或子包from mymodule.submodule import AnotherItem)获得某些内容,则可以将其导入到相应的__init__.py 文件中。

例如,假设您希望在submodule_impl.py 模块中定义的类CustomClass 可以直接从submodule 导入。您的 submodule/__init__.py 必须包含以下内容:

from .submodule_impl import CustomClass

然后您就可以直接从submodule 导入CustomClass(即from mymodule.submodule import CustomClass

【讨论】:

我在最后几段中多次看到您的建议,似乎这是将代码移出 __init__.py 的首选方式。我的问题是,我实际上并不希望 submodule_imp 成为公共 API 的一部分。就像,这是一个实现细节。 import mymodule.submodule.submodule_imp 在概念上是不可能的。有什么办法可以解决这个问题,还是我不应该担心它只是 Python 的本质,我应该相信库使用者会忽略未记录的内容? 后者 - Python 的理念是“我们都是成年人” - 除非你采取额外的步骤,否则人们无论如何都可以从你的模块中导入随机的东西 - 如果你只记录人们的方式 应该与你的包交互,这通常是人们会做的。【参考方案2】:

如果你想制作一个包,你必须了解 Python 如何将文件名转换为模块名。

文件mymodule.py 将作为mymodule 提供,假设解释器在Python 搜索路径的目录中找到它。如果您使用的是不区分大小写的文件系统,它也可能可以使用不同的大小写导入(但您应该避免使用这种依赖于系统的行为)。

包是一个包含__init__.py 文件的目录。最近有一些动作允许没有这些文件的包,但我将忽略这个答案的不太常见的情况。一个包成为 Python 中的一个模块,其代码来自 __init__.py 文件。所以文件mypackage/__init__.py可以导入为mypackage

__init__.py 文件直接在 Python 搜索路径中没有任何意义(好吧,我想你可以将它导入一个 __init__ 模块,但这可能是个坏主意)。

因此,根据您的情况,以下是适当的文件系统布局:

toplevel/
    mymodule/
        __init__.py     # put code here for mymodule
        submodule.py    # put code here for mymodule.submodule

只有 toplevel 文件夹应该在 Python 搜索路径中。

【讨论】:

我看到 Python 的人不鼓励在 mymodule/__init__.py 中放置重要的代码,例如。 Alex Martelli,这似乎与此不一致。 (不是说我一定同意……) 确实如此。更流行的方式是将mymodule 的实际代码放入未记录的子模块中,然后将其公共API 导入__init__.py 感谢您提供翔实的回答。遗憾的是,python 需要如此肮脏的 hack 来做一件显而易见的事情。 @SergeyRomanovsky - 我不会称其为 hack - 在您描述的情况下,您必须查看 三个 位置才能查看定义符号的位置(因为from mymodule import something 会查看mymodule.__init__mymodule.mymodulemymodule.mymodule.__init__)。 Python 3.3 确实重新访问了包模块并对其进行了重大更新。非常值得研究。 @SeanVieira:您说“Python 3.3 确实重新访问了包模块并对其进行了重大更新。值得研究”?你会详细说明吗?

以上是关于python模块层次结构命名约定的主要内容,如果未能解决你的问题,请参考以下文章

python_编程规范

Python:从项目层次结构中同一级别的另一个目录导入模块

分层多模块项目的 Maven 命名约定

python——pickle模块的详解

Python - ModuleNotFoundError:没有命名的模块

是否有命名单模块 Python 包的规则?