ModuleNotFoundError: No module named '__main__.xxx'; '__main__' is not a package问题

问题描述

今天写代码时碰到一个有趣的报错:"ModuleNotFoundError: No module named '__main__.xxx'; '__main__' is not a package"
问题发生在包内引用中。我的目录结构如下:
ModuleNotFoundError: No module named '__main__.xxx'; '__main__' is not a package问题
Wheel.py中定义了一个Wheel类,在Parser.py中我想导入这个类,于是写了这样一句:

line7:	from .Wheel import Wheel

Parser.py中点击Run之后,解释器提示以下错误:
ModuleNotFoundError: No module named '__main__.xxx'; '__main__' is not a package问题

根源定位

经过一番百度,在Stack Overflow中找到了答案——相对导入只有在父模块已经在当前运行环境中被导入过才有用
ModuleNotFoundError: No module named '__main__.xxx'; '__main__' is not a package问题
对于这一问题,官方文档intra-package-references也给出了解释:

Note that relative imports are based on the name of the current module. Since the name of the main module is always “main”, modules intended for use as the main module of a Python application must always use absolute imports.

这里揭示了报错的缘由,相对导入基于当前模块的名称,因为主模块总被命名为"__main__"。当我们从主模块启动时,Python就识图用"__main__"替换".",于是那句话实际便成了from __main__.Wheel import Wheel,这当然是找不到的。

解决办法

有两种:
一、使用绝对导入,这种绝逼不会错(也是官方文档给出的办法),即:

	from Core.Wheel import Wheel

二、保留当前写法,但不再以当前模块为主模块启动应用,例如:

	在Core同级目录下定义一个外部py文件,并在其中引入要引用的模块,此时目录变成:
	|---run.py
	|---Core
		|---__init__.py
		|---Wheel.py
		|---Parser.py

run.py中我们引入Parser类,因为此时的主模块变成了run,并且父模块已经被引入过,所以不再报错。

	# run.py
	from Core import Parser
	if __name__=='__main__':
		t = Parser.Parser()