我觉得这个问题之前已被多次提出过,但不知怎样,看似相关问题的答案都没有让我完全理解发生了什么。
情况:我创建了一个包,在该包中我有另一个包,我希望能够直接运行所有包,用于测试目的,即:
\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()
因此不再需要直接调用脚本,并且可以在单个脚本中组合多个运行。
答案 0 :(得分:3)
在没有破坏包的其他部分的所有导入的情况下,没有好的方法在文件名中运行包。相反,您应该使用-m
标志从顶级文件夹运行模块:
python -m package1.module1
以这种方式运行模块时,相对或绝对导入都应该有效(选择您喜欢的方式)。
请注意,如果你的项目中有循环导入(这样你作为脚本运行的模块也会从其他地方导入),解释器最终会得到两个模块副本,一个正在运行作为__main__
,另一个作为其正常名称。这可能非常尴尬并导致令人困惑的错误。
如果您经常将模块作为脚本运行,那么您可能应该创建一个新的顶级脚本模块,从模块中导入模块并运行所需的代码(就像您已经在做的那样)在main.py
)。这可以防止模块中充满代码可能存在两次,并且还可以让您从.pyc
文件加载缓存的字节码中受益(这可能会使您的程序启动速度更快)。