在这篇文章中,我将会解析 ImportError: attempted relative import with no known parent package
这个异常的缘由。当你在运行的python脚本。使用了相对引用方式 (相似import ..module
) 去引用包时,可能会出现这个异常。python
让咱们来看看发生这个异常的例子。算法
假设你有如下目录结构:shell
project
├── config.py
└── package
├── __init__.py
└── demo.py
复制代码
config.py
中包含一些应该在 demo.py
中使用的变量vim
count = 5
复制代码
from .. import config
print("The value of config.count is {0}".format(config.count))
复制代码
当咱们尝试运行demo.py
时,会遇到如下错误:less
E:\project> python demos/demo.py
Traceback (most recent call last):
File "demos/demo.py", line 1, in <module>
from .. import config
ImportError: attempted relative import with no known parent package
复制代码
python解释器抛出了没有父级包的异常。为何?post
让咱们看看python解释器是如何解析相关模块。从 PEP 328 中,咱们找到了关于 the relative imports
(相对引用)的介绍:spa
Relative imports use a module’s __name__ attribute to determine that module’s position in the package hierarchy. If the module’s name does not contain any package information (e.g. it is set to __main__ ) then relative imports are resolved as if the module were a top level module, regardless of where the module is actually located on the file system.code
相对导入经过使用模块的 __name__ 属性来肯定模块在包层次结构中的位置。若是该模块的名称不包含任何包信息(例如,它被设置为 __main__ ),那么相对引用会认为这个模块就是顶级模块,而无论模块在文件系统上的实际位置。orm
换句话说,解决模块的算法是基于__name__
和__package__
变量的值。大部分时候,这些变量不包含任何包信息 ---- 好比:当 __name__
= __main__
和 __package__
= None
时,python解释器不知道模块所属的包。在这种状况下,相对引用会认为这个模块就是顶级模块,而无论模块在文件系统上的实际位置。get
为了演示这个原理,咱们来更新一下代码:
print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
count = 5
复制代码
print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
from .. import config
print("The value of config.count is {0}".format(config.count))
复制代码
再次尝试运行一下,会获得如下输出:
E:\project> python demos/demo.py
__file__=demos/demo.py | __name__=__main__ | __package__=None
Traceback (most recent call last):
File "demos/demo.py", line 3, in <module>
from .. import config
ImportError: attempted relative import with no known parent package
复制代码
正如咱们所看到的,python解释器没有关于模块所属的包的任何信息( __name__
= __main__
和 __package__
= None
),所以它抛出了找不到父级包的异常。
咱们经过在其中建立一个新的空 __init__.py
文件来将项目目录转换为一个包。
咱们在项目目录的父目录中建立一个文件 main.py
toplevel
├── main.py
└── project
├── __init__.py
├── config.py
└── package
├── __init__.py
└── demo.py
复制代码
print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
import project.demos.demo
复制代码
执行一下新的示例,输出以下:
E:\toplevel>python main.py
__file__=main.py | __name__=__main__ | __package__=None
__file__=E:\toplevel\project\demos\demo.py | __name__=project.demos.demo | __package__=project.demos
__file__=E:\toplevel\project\config.py | __name__=project.config | __package__=project
The value of config.count is 5
复制代码
在 main.py
中导入 project.demos.demo
会设置相对引用的包信息( __name__
和 __package__
变量)。如今,python解释器能够成功解析 project\demos\demo.py
中的相对引用了。
咱们经过在 project
文件夹中建立一个新的空 __init__.py
来将 project
目录转换为一个包。
在 toplevel
目录下经过 -m
参数来调用python解释器,去执行 project.demos.demo
[1]
toplevel
└── project
├── __init__.py
├── config.py
└── package
├── __init__.py
└── demo.py
复制代码
再次执行:
E:\toplevel>python -m project.demos.demo
__file__=E:\toplevel\project\demos\demo.py | __name__=__main__ | __package__=project.demos
__file__=E:\toplevel\project\config.py | __name__=project.config | __package__=project
The value of config.count is 5
复制代码
运行该命令将自动设置包信息(__package__
变量)。如今,python解释器能够成功解析 project\ demos\demo.py
中的相对引用了(甚至认为 __name __
= __ main__
)。
[1] 译者注:注意使用 -m
参数的时候,后面指定的执行文件没有 .py
后缀
import-error-relative-no-parent
注:转载请保留下面的内容