最近在帮一个伙伴debug的时候发现,在一个package的内部,直接run一个.py文件,会报错说ValueError: Attempted relative import in non-package
。
原来这是因为,当我run的这个.py文件,如果它在某个package的文件夹下,而且这个.py文件夹内有诸如:
from . import
from .. import
相对导入(relative import)的语句,那么就会报错。
因为:
Relative imports use a module’s name attribute to determine that module’s position in the package hierarchy.
意思就是说,python import package都是根据每个module的__name__
来实现的。
比如说,有一个文件夹结构为:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
那么,如果(在这个package文件夹之外,比如package的同级文件夹下建立运行一个run.py)运行一个script,来导入moduleX模块,那么这个moduleX的__name__
就是.package.subpackage1.moduleX
,由于moduleX获得了前述名称,那么在moduleX.py
内部就可以有relative import的语句,比如说:
from .. import moduleA
而moduleX之所以能够获得的.package.subpackage1.moduleX
的__name__
attribute属性,前提是package
被python解释器识别成了一个package来处理(比如在package的同级文件夹下的运行的run.py有import package.subpackage1.moduleX
之类的语句)。可是,如果每一个被我直接run的python script都会被视作是top-level script。top-level script的__name__
被自动设置成__main__
。因此,如果我从package文件夹内部直接运行moduleA.py
这个脚本,那么它的__name__
就被置成了__main__
,python也不会把它当作一个package,其中的relative import的语句自然就无法起作用了。
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.
参考:
https://docs.python.org/3/tutorial/modules.html#intra-package-references
https://stackoverflow.com/questions/14132789/relative-imports-for-the-billionth-time#answer-14132912