我正在制作一个包,这个包中的模块在if __name__=='__main__':
块中有代码,用于测试。但是我尝试在这些模块中使用相对导入会导致错误。在
我读过这条线和其他十亿条线: Relative imports for the billionth time
在你把它标记为一个复制品之前,如果我想做的在Python3中是不可能的,那么我的问题是它为什么在Python2中工作,以及是什么促使了这个决定在Python3中引起如此大的麻烦?在
这是我的Python项目示例:
mypackage
- module1.py
- module2.py
- __init__.py
__init__.py
和{
module1.py
包含:
这在Python身上效果很好。我可以从计算机上的任何地方导入module1,也可以直接运行module1并运行if
块中的代码。在
然而,这种结构在Python3中不起作用。如果我尝试将模块导入其他位置,则会失败:
>>> from mypackage import module1
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\_MyFiles\Programming\Python Modules\mypackage\module1.py", line 1, in <module>
import module2
ModuleNotFoundError: No module named 'module2'
所以我试着把第一行改成from . import module2
,然后修复了它,这样我就可以从任何地方成功地导入模块了。但是,当我尝试直接将module1作为脚本运行时,会出现以下错误:
Traceback (most recent call last):
File "C:/_MyFiles/Programming/Python Modules/mypackage/module1.py", line 1, in <module>
from . import module2
ImportError: cannot import name 'module2' from '__main__' (C:/_MyFiles/Programming/Python Projects/pgui/mypackage/module1.py)
我不想每次在处理模块时都打开控制台并键入python -m myfile
,并希望直接将其作为脚本运行。在
我希望能够在不将父文件夹添加到PYTHONPATH的情况下使用Python2中的相对导入来处理模块
有没有更好的方法或解决这些问题的方法?在
Python包不仅仅是您将代码插入的文件夹,导入行为不仅仅取决于您将代码插入了哪个文件夹。在
直接运行文件时,不会将其作为包的一部分运行。包级初始化不会运行,Python甚至无法识别包的存在。在python2上,隐式相对导入的存在意味着裸的
import module2
将解析为绝对导入或隐式相对导入,从而隐藏了问题,但导入结构仍然是不完整的。在python3上,隐式的相对导入已经消失(这是有原因的),因此问题很快就会显现出来。在直接按文件名运行包的子模块并不能很好地工作。现在,我相信标准是要么使用
-m
,要么使用调用子模块功能的顶级入口点脚本。在无论如何,有一种方法可以通过文件名运行,但这是一个样板。PEP 366的设计者似乎打算使用
__package__ = 'appropriate.value'
赋值来使相对导入正常工作,但这实际上还不够,即使您修复了导入路径。您还必须手动初始化父包,否则当您尝试运行相对导入时,您将收到“SystemError:parent module'foo'not loaded,cannot perform relative import”(系统错误:父模块'foo'未加载,无法执行相对导入)。完整的样板看起来更像这在未来导入之类的内容之后,但在任何依赖于您的包的导入之前。在
我将把这个模板包装在一个可重用的函数中(使用堆栈操作来访问调用方的全局变量),只是如果您试图将该函数放在您的项目中的某个地方,那么在您修复了导入情况之前,您将无法导入该函数,而这正是您需要该函数来完成的。它可以作为可安装的依赖项工作。在
根据Module documentation,对于
__main__
模块,必须使用绝对导入。在所以只需将
module1.py
中的导入行改为:from mypackage import module2
其他一切都没变。在
我最终也遇到了类似的情况,这让我困扰了很多,直到我意识到模块和包导入是如何工作的。在
考虑以下结构
module1
和{module1.py
^{pr2}$module2.py
从。导入模块1
现在,如果我在包目录之外打开一个repl并尝试导入它,那么它就可以工作了
请在
sys.path
处做一个注释,因为您可以看到它包含了作为第一项的当前目录,这意味着我的所有导入都将首先在当前目录中搜索。在现在,如果我进入包目录,然后打开一个repl,并尝试进行相同的导入,看看会发生什么
如您所见,导入失败,失败的原因是当我试图从包导入模块时,python会在
sys.path
中搜索任何名为package
的包,因为我找不到任何包,因此导入失败。但是导入module1是可行的,因为它位于当前目录中。在在包外,我可以将脚本执行为
虽然我可以执行脚本,但这不是它应该如何使用。记住,包是需要共享的代码库,不应该有任何可以通过命令行直接执行的代码。包中的包和模块只需导入,导入后,您可以编写脚本,通过在其中添加
__name__
子句来执行这些脚本。在相关问题 更多 >
编程相关推荐