[英]How do I use “if __name__ == '__main__':” in a .bat file?
[英]How can I use relative importing in Python3 with an if __name__='__main__' block?
我正在制作一个包,并且这个包中的模块内部有代码if __name__=='__main__':
用于测试目的的块。 但是我尝试在这些模块中使用相对导入会导致错误。
我已经阅读了这个帖子和其他十亿人: 第 10 亿次的相对进口
在将其标记为重复之前,如果我想做的事情在 Python3 中是不可能的,那么我的问题是为什么它可以在 Python2 中工作,以及是什么促使决定在 Python3 中如此麻烦?
这是我的示例 Python 项目:
mypackage
- module1.py
- module2.py
- __init__.py
__init__.py
和module2.py
为空
module1.py
包含:
import module2
# module1 contents
if __name__=="__main__":
# Some test cases for the contents of this module
pass
这在 Python2 中工作正常。 我可以从我计算机上任何地方的其他项目导入 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
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 中的相对导入来处理模块
这些问题有没有更好的解决方法或解决方案?
根据模块文档,对于__main__
模块,您必须使用绝对导入。
请注意,相对导入基于当前模块的名称。 由于主模块的名称始终为“ main ”,因此用作 Python 应用程序主模块的模块必须始终使用绝对导入。
所以只需将module1.py
的导入行module1.py
为:
from mypackage import module2
其他一切都保持不变。
Python 包不仅仅是您将代码放入的文件夹,导入行为不仅仅取决于您将代码放入的文件夹。
当您直接运行您的文件时,您并没有将它作为包的一部分运行。 包级初始化不会运行,Python 甚至无法识别包的存在。 在 Python 2 上,隐式相对导入的存在意味着裸import module2
将解析为绝对导入或隐式相对导入,隐藏了问题,但导入结构仍然被破坏。 在 Python 3 上,隐式相对导入消失了(有充分的理由),因此问题立即可见。
直接按文件名运行包的子模块效果不佳。 现在,我认为标准是使用-m
或使用调用子模块功能的顶级入口点脚本。
无论如何,有一种方法可以让按文件名运行,但它有很多样板。 PEP 366的设计者似乎打算通过__package__ = 'appropriate.value'
赋值来使相对导入正常工作,但这实际上还不够,即使您修复了导入路径。 您还必须手动初始化父包,否则一旦您尝试运行相对导入,就会收到“系统错误:父模块 'foo' 未加载,无法执行相对导入”。 完整的样板看起来更像
import os.path
import sys
if __name__ == '__main__' and __package__ is None:
__package__ = 'mypackage'
right_import_root = os.path.abspath(__file__)
for i in range(__package__.count('.') + 2):
right_import_root = os.path.dirname(right_import_root)
# sys.path[0] is usually the right sys.path entry to replace, but this
# may need further refinement in the presence of anything else that messes
# with sys.path
sys.path[0] = right_import_root
__import__(__package__)
这在未来导入之类的东西之后,但在任何依赖于您的包的导入之前。
我会将这个样板包装在一个可重用的函数中(使用堆栈操作来访问调用者的全局变量),除了如果您尝试将该函数放在项目中的某个位置,您将无法导入该函数,直到您修复了您的导入情况,您需要该功能来完成。 它可能用作可安装的依赖项。
我最终遇到了类似的情况,这让我很困扰,直到我意识到模块和包导入应该如何工作。
考虑以下结构
mydir
- project
- __init__.py
- module1.py
- module2.py
module1
和module2
内容如下所示
模块1.py
print("moudule1")
模块2.py
从 。 导入模块1
print("Module 2")
if __name__ == '__main__':
print("Executed as script")
现在,如果我在包目录外打开一个 repl 并尝试使其导入工作
Python 3.6.7 (default, Oct 22 2018, 11:32:17)
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from package import module2
Module 1
Module 2
>>> sys.path
['', '/usr/lib/python36.zip', '/usr/lib/python3.6', '/usr/lib/python3.6/lib-dynload', '/home/rbhanot/.local/lib/python3.6/site-packages', '/usr/local/lib/python3.6/dist-packages', '/usr/lib/python3/dist-packages']
记下sys.path
,因为您可以看到它包含我所在的当前目录作为第一项,这意味着将首先在当前目录中搜索我的所有导入。
现在,如果我进入包目录,然后打开一个 repl,并尝试进行相同的导入,看看会发生什么
Python 3.6.7 (default, Oct 22 2018, 11:32:17)
[GCC 8.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from . import module2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'module2'
>>> import module2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/rbhanot/python-dotfiles/python3/modules-packages/mydir/package/module2.py", line 1, in <module>
from . import module1
ImportError: attempted relative import with no known parent package
>>> import module1
Module 1
>>>
如您所见,导入失败,失败的原因是当我尝试从包中导入模块时,python 在sys.path
搜索以查找名称为package
任何package
,因为我找不到任何包,因此导入失败。 但是导入 module1 是有效的,因为它是在当前目录中找到的。
在包外,我可以将脚本执行为
python3 -m package.module2 2 ↵
Module 1
Module 2
Executed as script
虽然我可以执行脚本,但这不是它应该如何使用的。 请记住,包是需要共享的代码库,不应包含任何可通过命令行直接执行的代码。 包内的包和模块只是被导入,然后在导入后你可以编写你的脚本,通过在命令行中放入__name__
子句来执行。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.