从不同层次导入 Python 模块

Jak*_*evi 4 python import module package python-3.x

在我的 git 存储库的顶层,我有以下文件结构:

miscellaneous Dockerfiles, readme, etc
Code/
    training.py
    data/
        generate.py
        tasksets.py
Run Code Online (Sandbox Code Playgroud)

有时,当我将模块作为脚本运行时,我想generate从模块内部导入模块,因此包括以下导入:tasksetstasksetstasksets

import generate
Run Code Online (Sandbox Code Playgroud)

其他时候我想tasksets从模块内部导入模块training,因此training包含以下导入:

import tasksets
Run Code Online (Sandbox Code Playgroud)

然而,这个设置给我带来了问题。当我作为脚本运行时tasksets可以很好地导入,但是如果我在作为脚本运行时导入内部,则会抛出错误(我认为是因为在默认路径中找不到脚本)。我尝试过使用文件、相对导入等查看各种其他 StackOverflow 问题和答案。目前,我的解决方法是在内部使用以下几行:generatetasksetstasksetstrainingtrainingtraininggenerate__init__.pytasksets

if __name__ == "__main__": import generate
else: from data import generate
Run Code Online (Sandbox Code Playgroud)

但这感觉不太对(而且我的 IDE 也不喜欢它)。请有人解释如何使用正确的__init__.py文件分类和导入语句,以便我可以在作为脚本generate运行时导入,也可以在作为脚本运行时导入?tasksetstasksetstraining

Aro*_*unt 5

你最好使用经典的 Python 模块/包架构。

projectname/
    __init__.py
    __main__.py
    data/
        __init__.py
        generate.py
        tasksets.py
Run Code Online (Sandbox Code Playgroud)

要使用您的应用程序,请进入projectname/../目录(上一级projectname/)并运行python -m projectname。这将执行projectname/__main__.py.


你会在其中__main__.py写下类似的内容:

from projectname.data import generate
from projectname.data import tasksets

if __name__ == '__main__':
    generate.foo()
    tasksets.bar()
Run Code Online (Sandbox Code Playgroud)
  1. 您将使用绝对导入路径(以模块名称和点开头,projectname.
  2. 您将从以下位置导入您的子模块if __name__ == '__main__'
  3. __main__.py将是您的应用程序/脚本的唯一入口点。

在任何其他文件中,您将使用相同的语法和路径来导入其他模块:

data/generate.py:

from projectname.data import tasksets

def foo():
    print('SPAM!')
    tasksets.bar()
Run Code Online (Sandbox Code Playgroud)

我不太喜欢这一点,但我不确定是否有任何政治人物会否认这一点,

在你的projectname/__init__.py文件中你可以写:

from projectname.data import generate
from projectname.data import tasksets
Run Code Online (Sandbox Code Playgroud)

因此,您的两个子模块将被导入到您的主作用域中__init__.py,因此您可以从此作用域导入子模块,例如

data/generate.py:

from projectname import generate
Run Code Online (Sandbox Code Playgroud)

但同样,我并不真正喜欢这种做法(因为显式比隐式更好。


最后但并非最不重要的,

  • 你也可以使用python projectname/__main__.py命令,但我仍然推荐python -m projectname
  • 您可以使用setuptools创建一个setup.py文件来在系统上“安装”您的应用程序,然后只需运行命令即可运行它。projectname