本文介绍了在包中运行模块,导入子包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我觉得这个问题已经被问过很多次了,但是某种程度上看似相关的问题的答案都无法使我完全理解正在发生的事情.

I get the sense this question has been asked many times before, but somehow none of the answers to seemingly related questions get me to fully understand what's going on.

情况:我创建了一个程序包,在该程序包中有另一个程序包,我希望能够直接运行所有程序包,以进行测试,即:

The situation: I create a package and inside that package I have another package and I want to be able to run all of them directly, for testing purposes i.e.:

\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:

And 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:

And module_2.py:

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

__ init__.py为空.这使我可以从根目录运行main.py,并且可以运行.我也可以从其自己的文件夹中运行module_2.py.但是我无法运行module_1.py,因为它抱怨没有package_1.尽管从技术上讲,它本身在package_1中,但这是有道理的.但是,如果我删除该前缀,它将破坏main,这也很有意义.

The __init__.py are empty. This allows me to run main.py from the root and it works. I can also run module_2.py from its own folder. But I can't run module_1.py since it complains there is no package_1. That makes some sense, although technically it is itself in package_1. But if I remove that prefix, it breaks main, which also makes some sense.

如何解决此问题?我尝试用以下方式替换module_1.py中的导入:

How to fix this? I tried replacing the import in module_1.py by:

import .package_2.module_2

但这给我带来了一个我不完全理解的错误:

But that gets me an error I don't fully understand:

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

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

What is the right approach to get all of the packages and modules working as intended? Is it something that should be solved in __init__.py? Or should I simply avoid nesting packages like this and install them all (after providing a setup.py)?

@Blckknght建议运行:

@Blckknght suggested running:

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

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

From the root directory. That works, in that all the code is run as expected. I also updated the import in module_1.py to:

from .package_2.module_2 import func_2

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

And finally, @jonilyn2730 provided the suggestion to make the main body callable from other scripts by putting it inside a main() function. For example, module_1.py would be:

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

在这个简单的示例中,它没有什么区别,但是在其他脚本中却允许这样做:

In this trivial example, it makes little difference, but it allows this in other scripts:

from package_1.module_1 import main
main()

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

So the script no longer has to be called directly and multiple runs can be combined in a single script.

推荐答案

没有一种好的方法可以通过文件名在程序包中运行模块而不破坏程序包其他部分的所有导入.相反,您应该使用-m标志从顶级文件夹中运行该模块:

There's no good way to run a module in a package by file name without breaking all imports of other parts of the package. Instead, you should run the module it from the top level folder using the -m flag:

python -m package1.module1

以这种方式运行模块时,相对导入或绝对导入都应起作用(选择任何您喜欢的选项).

When you run the module this way, both relative or absolute imports should work (pick whichever you prefer).

请注意,如果您的项目中有循环导入(以便从脚本中运行的模块也可以从其他位置导入),则解释器将最终获得该模块的两个副本,其中一个作为__main__,另一个作为其常规名称.这可能很尴尬,并导致令人困惑的错误.

Beware though that if you have circular imports in your project (so that the module you're running as the script also gets imported from somewhere else), the interpreter will end up with two copies of the module, one running as __main__ and the other as its normal name. This can be very awkward and cause confusing bugs.

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

If you're running the module as a script a lot, you probably should make a new top-level script module that import the module from the package and runs the desired code (like you're already doing in main.py). This prevents the module full of code from potentially existing twice, and also lets you benefit from cached bytecode being loaded from a .pyc file (which may make your program a bit faster to start up).

这篇关于在包中运行模块,导入子包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-19 10:55