在包中运行模块,导入子包

时间:2017-08-23 04:51:35

标签: python python-3.x module package

我觉得这个问题之前已被多次提出过,但不知怎样,看似相关问题的答案都没有让我完全理解发生了什么。

情况:我创建了一个包,在该包中我有另一个包,我希望能够直接运行所有包,用于测试目的,即:

\main.py
\package_1\__init__.py
\package_1\module_1.py
\package_1\package_2\__init__.py
\package_1\package_2\module_2.py

其中main.py:

from package_1.module_1 import func_1
func_1()

并且module_1.py:

from package_1.package_2.module_2 import func_2
def func_1():
    func_2()
if __name__ == "__main__":
    func_1()

并且module_2.py:

def func_2:
    print ("This works")
if __name__ == "__main__":
    func_2()

__init__.py为空。这允许我从root运行main.py并且它可以工作。我也可以从自己的文件夹中运行module_2.py.但我无法运行module_1.py,因为它抱怨没有package_1。这有点道理,虽然从技术上来说它本身就是package_1。但是,如果我删除该前缀,它会破坏主要,这也是有道理的。

如何解决这个问题?我尝试将module_1.py中的导入替换为:

import .package_2.module_2

但这让我感到错误,我不能完全理解:

ModuleNotFoundError: No module named '__main__.package_2'; '__main__' is not a package

使所有软件包和模块按预期工作的正确方法是什么?它是否应该在__init__.py中解决?或者我应该简单地避免嵌套这样的包并安装它们(在提供setup.py之后)?

编辑:

@Blckknght建议跑步:

python -m package_1.module_1
python -m package_1.package_2.module_1

从根目录。这是有效的,因为所有代码都按预期运行。我还将module_1.py中的导入更新为:

from .package_2.module_2 import func_2

最后,@ jonilyn2730提供了建议,通过将主体放在main()函数中来使主体可以从其他脚本调用。例如,module_1.py将是:

from package_1.package_2.module_2 import func_2
def func_1():
    func_2()
def main():
    func_1()
if __name__ == "__main__":
    main()

在这个简单的例子中,它没什么区别,但它允许在其他脚本中使用它:

from package_1.module_1 import main
main()

因此不再需要直接调用脚本,并且可以在单个脚本中组合多个运行。

1 个答案:

答案 0 :(得分:3)

在没有破坏包的其他部分的所有导入的情况下,没有好的方法在文件名中运行包。相反,您应该使用-m标志从顶级文件夹运行模块:

python -m package1.module1

以这种方式运行模块时,相对或绝对导入都应该有效(选择您喜欢的方式)。

请注意,如果你的项目中有循环导入(这样你作为脚本运行的模块也会从其他地方导入),解释器最终会得到两个模块副本,一个正在运行作为__main__,另一个作为其正常名称。这可能非常尴尬并导致令人困惑的错误。

如果您经常将模块作为脚本运行,那么您可能应该创建一个新的顶级脚本模块,从模块中导入模块并运行所需的代码(就像您已经在做的那样)在main.py)。这可以防止模块中充满代码可能存在两次,并且还可以让您从.pyc文件加载缓存的字节码中受益(这可能会使您的程序启动速度更快)。

相关问题