解决python相对导入出现错误:Attempted relative import beyond toplevel package
2017-12-21 13:58
525 查看
相对导入的官方解释(中文):http://python3-cookbook.readthedocs.io/zh_CN/latest/c10/p03_import_submodules_by_relative_names.html
相对导入解决的问题就是消除绝对路径带来的硬编码问题,具体请看文档。
但是在使用相对导入的时候会出来各种错误,其中最让人费解的可能就是:Attempted relative import beyond toplevel package
其实这个原因是因为包的层次引起的,跟包的路径查找有很大的关系。
先来聊聊python的包的查找方式:
简单的来说,Python 有个PYTHONPATH环境变量和安装路径,这个环境变量和安装路径决定了sys.path(是一个list类型)的值,而python查找包时,python会查找当前路径,然后会按顺序查找sys.path中的路径。
在这里需要注意的是,python2中,是按上述方式进行的(先查找当前路径,再到sys.path),但是在python3中,是先查找sys.path,找不到再查找当前路径的。
具体可以看官方文档(中文):http://www.pythondoc.com/pythontutorial3/modules.html
如果你看了上面的这边官方文档,你一定看到了python找打印包路径的方法:
现在让我们通过这命令来解释,在使用相对导入的时候,为什么会出现:Attempted relative import beyond toplevel package
先来看一下测试目录结构:
.
├── run.py
└── test
├── dir1
│ ├── __init__.py
│ └── moudle1
│ ├── a.py
│ └── __init__.py
├── dir2
│ ├── __init__.py
│ ├── __init__.pyc
│ └── moudle2
│ ├── b.py
│ ├── b.pyc
│ ├── __init__.py
│ └── __init__.pyc
├── run.py
└── test.py
a.py中有一个函数:
def test():
pass
现在,要实现的是,在 b. py 中引用 a.py 的内容:
print __name__
from ...dir1.moudle1.a import test
注意到,有两个 run.py 和 test/run.py
这两个文件的代码都很简单,只有一行代码:
from test.dir2.moudle2.b import test然后分别运行上面的run脚本:
python test/run.py 这个命令将会打印 b 的包路径并且报错
从打印的包路径来看,这个包的完整路径只是到dir2就没了。而我们的相对导入在解析相对路径的时候,是根据所在脚本的包路径来解析的。
仔细分析一下这个路径:
从这个表就可以看出来,三级目录 ... (三个点) 已经超出了最顶层的目录结构。因此才会报错。
再看下一个命令:
python run.py 这个命令打印的 b 的包路径是:
分析下来就是:
通过上面的比较,可以知道,包路径跟运行脚本所在的目录有关系,而更加本质的原因是,跟包的查找路径有关系(python会在运行脚本所在的路径查找包)。对此有疑惑的同学,也可以试试,比如:把不同的包路径添加到 sys.path 中,然后在其他地方执行run脚本,是可以得到同样的结果的。
最后,总结一下,在使用相对导入的时候一定要注意包路径和包的查找路径。要在最顶层的目录添加到 sys.path 中,或者 在最顶层运行脚本。
相对导入解决的问题就是消除绝对路径带来的硬编码问题,具体请看文档。
但是在使用相对导入的时候会出来各种错误,其中最让人费解的可能就是:Attempted relative import beyond toplevel package
其实这个原因是因为包的层次引起的,跟包的路径查找有很大的关系。
先来聊聊python的包的查找方式:
简单的来说,Python 有个PYTHONPATH环境变量和安装路径,这个环境变量和安装路径决定了sys.path(是一个list类型)的值,而python查找包时,python会查找当前路径,然后会按顺序查找sys.path中的路径。
import sys print sys.path通过上面代码,你可以看到默认的查找路径。
在这里需要注意的是,python2中,是按上述方式进行的(先查找当前路径,再到sys.path),但是在python3中,是先查找sys.path,找不到再查找当前路径的。
具体可以看官方文档(中文):http://www.pythondoc.com/pythontutorial3/modules.html
如果你看了上面的这边官方文档,你一定看到了python找打印包路径的方法:
print __name__
现在让我们通过这命令来解释,在使用相对导入的时候,为什么会出现:Attempted relative import beyond toplevel package
先来看一下测试目录结构:
.
├── run.py
└── test
├── dir1
│ ├── __init__.py
│ └── moudle1
│ ├── a.py
│ └── __init__.py
├── dir2
│ ├── __init__.py
│ ├── __init__.pyc
│ └── moudle2
│ ├── b.py
│ ├── b.pyc
│ ├── __init__.py
│ └── __init__.pyc
├── run.py
└── test.py
a.py中有一个函数:
def test():
pass
现在,要实现的是,在 b. py 中引用 a.py 的内容:
print __name__
from ...dir1.moudle1.a import test
注意到,有两个 run.py 和 test/run.py
这两个文件的代码都很简单,只有一行代码:
from test.dir2.moudle2.b import test然后分别运行上面的run脚本:
python test/run.py 这个命令将会打印 b 的包路径并且报错
包路径:dir2.moudle2.b
Traceback (most recent call last): File "test/run.py", line 1, in <module> from dir2.moudle2.b import test File "~/Code/python/mytest/test/dir2/moudle2/b.py", line 3, in <module> from ...dir1.moudle1.a import test ValueError: Attempted relative import beyond toplevel package
从打印的包路径来看,这个包的完整路径只是到dir2就没了。而我们的相对导入在解析相对路径的时候,是根据所在脚本的包路径来解析的。
仔细分析一下这个路径:
dir2 | moudle2 | b |
..(父目录) | .(当前目录) | 包名 |
再看下一个命令:
python run.py 这个命令打印的 b 的包路径是:
包路径:test.dir2.moudle2.b
分析下来就是:
test | dir2 | moudle2 | b |
...(三级目录) | ..(父目录) | .(当前目录) | 当前目录 |
最后,总结一下,在使用相对导入的时候一定要注意包路径和包的查找路径。要在最顶层的目录添加到 sys.path 中,或者 在最顶层运行脚本。
相关文章推荐
- Python包的相对导入时出现错误的解决方法
- Python:Relative import 相对路径 ValueError: Attempted relative import in non-package
- Python:Relative import 相对路径 ValueError: Attempted relative import in non-package
- 【已解决】Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level
- 解决bs4在Python 3.5下出现“ImportError: cannot import name 'HTMLParseError'”错误
- 【已解决】Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level
- python的package import 以及相对导入和绝对导入
- 【已解决】Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level
- Python在cmd中用easy_install django导入时出现错误,待解决
- python引入pytesseract报错:ValueError: Attempted relative import in non-package
- 【已解决】Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level
- [译][python]ImportError:attempted relative import with no known parent package
- attempted relative import beyond top-level package
- 网络爬虫在Python 3.5下出现“ cannot import name 'HTMLParseError'”错误解决办法
- Python中的Attempted relative import in non-package问题
- 解决bs4在Python 3.6下出现“ImportError: cannot import name 'HTMLParseError'”错误
- python:Attempted relative import in non-package
- python的package import 以及相对导入和绝对导入
- 【已解决】Python脚本运行出现语法错误:IndentationError: unindent does not match any outer indentation level
- ubuntu python import caffe出现错误解决方法