前言

在这篇文章中,我将会解析 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. 2018-2019-2 《网络对抗技术》Exp2 后门原理与实践 Week3 20165326

    Exp2 后门原理与实践 目录 1. 实验原理 2. 实验内容 3. 问题回答 4. 心得体会 实验原理简介 后门:不经过正常流程而访问系统的通道 ncat:底层工具,进行基本的TCP UDP数据收发 ...

  2. better-scroll

    better-scroll会将默认事件阻止掉,如果自己写的部分需要有点击事件,需要在参数里加上click:true. 同时,在PC上或某些手机端,由于未成功将touchend事件move掉,点击事件会 ...

  3. foreach 使用 引用& $value . 使用 unset($value)

    1.知识点: 2. 例子 2.1 例子1 . $arr 引用循环, 赋值变量是 &$v ,第一个循环使用后 ,没有 使用unset($v) , $arr2 正常循环, 赋值变量是 $v ,  ...

  4. React Navigation基本用法

    /** * Created by apple on 2018/9/23. */ import React, { Component } from 'react'; import {AppRegistr ...

  5. nova98 假区域链 骗人项目(vexx.pro的前身)

    首先,我是受害者. nova98前期是vexx.pro,前期推广送比特龙, 送3个,然后推广一个新人可以再拿到1.5个. 然后呢,现在就又推出一个新网站,nova98,把之前推广的人领到币全部清零,而 ...

  6. 【解决】Server Tomcat v7.0 Server at localhost failed to start.

    Server Tomcat v7.0 Server at localhost failed to start. 出现此原因是因为servlet-name不匹配 修改一致即可

  7. MySQL之UNION与UNION ALL

    数据表中的数据如下: UNION: 可以获取books表与articles表中所有不同的title,如果两个表中title相同的只会显示一个.  UNION ALL : 可以获取books表与arti ...

  8. JavaSpcript基础

    函数 代码的复用:写一遍多次使用>把特定的功能语句打包放在一起 语法:function 名字(0,1,1多个参数){ 执行的语句 } 返回值return,把语句返回给函数 例子: functio ...

  9. cobbler批量化安装系统

  10. vue中的$route和$router的区别

    1. $route是一个对象 可以获取当前页面的路由的路径query.params.meta等参数: 2.$router是VueRouter的一个实例对象 在options中可以获取路由的routes ...