前言

在这篇文章中,我将会解析 ImportError: attempted relative import with no known parent package 这个异常的原因。当你在运行的python脚本。使用了相对引用方式 (类似import ..module) 去引用包时,可能会出现这个异常。

让我们来看看发生这个异常的例子。

问题

假设你有以下目录结构:

project
├── config.py
└── demos
├── __init__.py
└── demo.py

config.py 中包含一些应该在 demo.py 中使用的变量

  • project/config.py
count = 5
  • project/demos/demo.py
from .. import config
print("The value of config.count is {0}".format(config.count))

当我们尝试运行demo.py时,会遇到以下错误:

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解释器抛出了没有父级包的异常。为什么?

让我们看看python解释器是如何解析相关模块。从 PEP 328 中,我们找到了关于 the relative imports(相对引用)的介绍:

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.

相对导入通过使用模块的 __name__ 属性来确定模块在包层次结构中的位置。如果该模块的名称不包含任何包信息(例如,它被设置为 __main__ ),那么相对引用会认为这个模块就是顶级模块,而不管模块在文件系统上的实际位置。

换句话说,解决模块的算法是基于__name____package__变量的值。大部分时候,这些变量不包含任何包信息 —- 比如:当 __name____main__ 和 __package__ = None 时,python解释器不知道模块所属的包。在这种情况下,相对引用会认为这个模块就是顶级模块,而不管模块在文件系统上的实际位置。

为了演示这个原理,我们来更新一下代码:

  • project/config.py
print('__file__={0:<35} | __name__={1:<20} | __package__={2:<20}'.format(__file__,__name__,str(__package__)))
count = 5
  • project/package/demo.py
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
└── demos
├── __init__.py
└── demo.py
  • toplevel/main.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
└── demos
├── __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__ )。

注意使用 -m 参数的时候,后面指定的执行文件没有 .py 后缀。

注2:

实际使用中还有一个可能会报出这种错误, 就是执行代码的路径不对。

E:\toplevel>python -m project.demos.demo

一定要在project的上一级目录执行这个命令。

执行代码出现ImportError:attempted relative import with no known parent package的更多相关文章

  1. Python工程:ImportError: attempted relative import with no known parent package

    Python工程:ImportError: attempted relative import with no known parent package 解决方法: 1.对每个目录创建的时候都选择创建 ...

  2. 执行文件异常报错:ImportError: attempted relative import with no known parent package

    这个问题困扰了我很久了,网上的解决方法都很一致,找来找去都是一样的解决方法,在导入包的文件和执行文件加入 1 print('__file__={0:<35} | __name__={1:< ...

  3. ImportError: attempted relative import with no known parent package

    或者检查所导包是否存在__init__.py文件,没有则添加上即可使当前文件夹变为包.

  4. python:Attempted relative import in non-package

    problem:Attempted relative import in non-package 所谓相对路径其实就是相对于当前module的路径,但如果直接执行脚本,这个module的name就是“ ...

  5. ValueError: Attempted relative import in non-package

    执行:python deom/scripts/populate.py ValueError: Attempted relative import in non-package solve:python ...

  6. python相对包导入报“Attempted relative import in non-package”错误

    文章是从stackoverflow翻译过来的,原文地址:Relative imports for the billionth time 本文要在原理上解决  python当中相对包导入出现的问题. 问 ...

  7. Python 相对导入attempted relative import beyond top-level package

    ValueError: attempted relative import beyond top-level package 假设有如下层次包目录 project/ __init__.py mypac ...

  8. Python ValueError: Attempted relative import in non-package Relative import相对引用 错误

    包含相对路径import的python脚本不能直接运行,只能作为module被引用. 例如 from . import mod1 有这样代码的文件只能最为moulule为不能直接运行.相对路径就是相对 ...

  9. ValueError: attempted relative import beyond top-level package

    python 项目 在pycharm中, 在某个文件夹下: 右键--> mark directory as --> source root 如何在python脚本或者shell中 用代码实 ...

随机推荐

  1. 【转】Android-Input 键盘设备

    https://source.android.com/devices/input/keyboard-devices 键盘设备 Android 支持各种键盘设备,包括特殊功能小键盘(音量和电源控制),紧 ...

  2. DFS和BFS

    BFS 代码步骤: 1.写出每个点和每个点的邻接点的对应关系 2.方法参数:传一个对应关系和起始点 3.创建一个队列,然后每次都移除第一个,然后把移除的邻接点添加进去,打印取出的第一个,然后循环,一直 ...

  3. 北大poj- 1007

    DNA排序 逆序数可以用来描述一个序列混乱程度的量.例如,“DAABEC”的逆序数为5,其中D大于他右边的4个数,E大于他右边的1个数,4+1=5:又如,“ZWQM”的逆序数为3+2+1+0=6. 现 ...

  4. html之跳转锚

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  5. Altium Designer 10 快捷键笔记

    一.放置.走线类: 1.交互式走线(Track):P T 2.铺铜(Fill):P F 3.大面积铺铜(Polygon):P G 4.自动扇出:元件封装上右键,C F 二.编辑类 1.调整铺铜(Pol ...

  6. 【EMV L2】2CS.001.00 ~ 2CS.007.00

    测试case要求,对于T=0和T=1卡,命令中是否存在Le是有差异的: - Select: Mandatory Command00 A4 04 00 Lc Command Data LeLc = 05 ...

  7. python中random模块的使用

    import random random.random() 产生0-1间的随机小数 >>> res = random.random() >>> print(res) ...

  8. 对C语言指针的理解

    一个小程序引发对于C语言指针的思考: #include <bits/stdc++.h> using namespace std; void my_swap (int* a,int* b) ...

  9. SQLI DUMB SERIES-17

    (1)无论怎么输入username,都没有回显.尝试改变password的输入.找到了闭合方式:单引号 (2)报错注入: 爆库名 admin&passwd=admin' and extract ...

  10. H5视频直播扫盲

    H5视频直播扫盲 2016-05-25 • 前端杂项 • 14 条评论 • lvming19901227 视频直播这么火,再不学就out了. 为了紧跟潮流,本文将向大家介绍一下视频直播中的基本流程和主 ...