python相对包导入报“Attempted relative import in non-package”错误
文章是从stackoverflow翻译过来的,原文地址:Relative imports for the billionth time
本文要在原理上解决 python当中相对包导入出现的问题。
问题描述
在win7、32位的电脑上,运行python2.7.3,经常会出现"Attempted relative import in non-package"这样的问题。
为了解决这个问题,我(提问的人)搜索了以下网站,当然还有更多的网站
- http://www.python.org/dev/peps/pep-0328/
- http://docs.python.org/2/tutorial/modules.html#packages
- Python packages: relative imports
- python relative import example code does not work
- Ultimate answer to relative python imports
- Relative imports in Python
- Python: Disabling relative import
我根据pep-0328建立了以下的目录结构
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
而且按照这个目录当中的要求,建立了了spam( moduleY.py中)和eggs(moduleZ.py中)函数,现在想要在moduleX.py当中调用别的函数或模块。很显然,当我运行的时候,并没有成功。
上面的第四个URL当中有如下信息,这个答案比较接近真相,但是其中的有些概念还是很难理解:
相对导入使用模块的名称属性来决定模块在包层次结构中的位置,如果模块的名称不包含任何包信息(例如:被设置成‘main’),那么相对导入则被解析为最顶层的位置,不管这个时候这个模块实际上位于文件系统中的什么位置。
所以,如何让我运行的python程序不再返回 "Attempted relative import in non-package"问题?python为什么会报这个错误?这里的‘non-package’是什么意思?为什么以及如何去定义一个‘package’?同时解释一下-m选项?
回答:
什么是脚本?什么是模块?(script vs module)
直接运行一个文件和在别的文件中导入这个文件是有很大区别的,仅仅知道一个文件在目录中的位置并不意味着python程序就认为它在什么位置。这是由python用何种方式加载(运行或者导入.run or import)这个文件来决定的。
python有两种加载文件的方法:一种是作为顶层的脚本,另一种是当做模块。如果你直接执行这个程序,那么这个文件就被当做是顶层脚本来执行了,在命令行里面输入 python myfile.py 就是这个情况。如果你输入python -m myfile.py或者在其他的文件当中使用import来导入这个文件的时候,它就被当做模块来导入。在同一时间里,只有一个顶层脚本,顶层脚本可以这样解释:它是一个能够让你的程序从这里开始的python文件。
【文件(file)是一种无区别的叫法,如何运行和处理这个文件,决定了它的性质。直接从这个文件运行,那么这个文件就叫做脚本。导入这个文件,那么这个文件就是模块(module)。另外,一个包(package)是一个包含有__init__.py的文件夹,下面会用到】
命名(naming)
当一个文件被加载进来,它就有一个名称(这个名称存储在__name__属性当中)。如果这个文件被当做一个顶层脚本来进行加载,那么它的名字就是__main__。如果它被当做一个模块加载,那么它的名称就是文件名称,加上它所在的包名,以及所有的顶层的包名,这些名称中间是用点号隔开的。
比如下面的例子
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
比如你导入moduleX(from package.subpackag1 import moduleX),它的名称就package.subpackage1.mouleX。如果你导入moduleA的时候(from package import moduleA),它的名称就是package.moudleA。
(注:这里是使用包导入,即把package以及里面的所有文件看做一个包,导入的时候使用from ... import ...的形式来进行,我们调用第三方包的时候就是这种情况),
但是,当你直接从命令行里面运行moduleX的时候,他的名称则被替换为__main__。如果你直接从命令行运行moduleA,它的名称也是__main__。当一个模块被当做一个顶层脚本来执行的时候,它原来的名称则会被__main__取代。
不通过包导入访问一个模块
这里有一个额外的问题:模块的名称取决于从它所在的目录中直接导入的,还是通过包导入的。这种情况只有在该包中运行python文件,并且试图导入这个包当中的其它文件的时候才有意义。(可以发现,上面的介绍的包导入总是在外面来访问一个模块)
举个例子,如果你在package/subpackage1目录当中打开python解释器,然后输入import moduleX,那么moduleX的名称就是moduleX,而不是package.subpackage1.moduleX。这是因为python把当前的目录添加到了搜索路径上面。如果它发现被包含的模块在当前的目录当中,它将不知道该目录也是模块的一部分,包的信息不会出现在模块名称当中。
当你直接运行python解释器(比如cmd里面输入python,然后进入python解释器,或者使用ipython)。在这种情况下,这种交互式的终端的名称是__main__。
现在,你的问题有了一个关键性的答案:如果一个模块名称当中没有点号,那么它就不会被当做是一个包。不管这个文件在磁盘的什么位置。所有关键在于,它的名称是什么,而这个名称取决于你如何加载它。
那么现在看一下你在其他的URL当中的引用的这句话:
相对导入使用模块的名称属性来决定模块在包层次结构中的位置,如果模块的名称不包含任何包信息(例如:被设置成‘main’),那么相对导入则被解析为最顶层的位置,不管这个时候这个模块实际上位于文件系统中的什么位置。
相对导入...
相对导入使用模块的名称去决定它在一个包中的位置。当你使用了一个像这样的相对导入:from .. import foo,这里的点号表明在包的层次结构当中上升几个层级。比如,现在模块的名称是package.subpackage1.moudleX,然后..moduleA中的两个点号表示的是上升两个层级,到达package,然后package和moduleA结合,最终成为package.moduleA。要让from .. import这样的相对导入正常工作,模块的名称中至少要有和语句中相对应的“点”的数量。
...只能用在相对导入当使用
如果你的模块的名称是__main__,那么它就不被认为是在一个包当中,因为它的名称当中不含有“点”,所以你不能在它的里面使用from .. import。如果你使用了这个语句,那么程序就会报“relative-import in non-package"错误。
脚本不能包含相对导入:
当你直接运行moduleX或者是在命令行终端里运行程序的时候,这个时候模块的名称都是__main__,这就表明你不能使用相对导入。因为他们的名称表示他们并不在一个包当中。注:当你运行的python目录就是你模块所在的目录的时候,上面这种情况也会发生,这种情况下python过早的寻找当前目录的模块,并没有认为他们也是包的一部分。
当你运行交互式的解释器的时候,交互式进程的名称永远是__main__,因此你不能在交互式进程当中使用相对导入。相对导入只能在模块文件当中使用。
两个解决方法:
1:如果你想直接运行moduleX,但是你又想把它当做一个包的一部分,你可以使用python -m package.subpackage.moduleX. -m参数告诉python把它当做一个模块来加载,而不是顶层的脚本。
2:或许你并不想直接运行moduleX,你想在其它的脚本当中使用moduleX的函数,比如说这个脚本是myfile.py。如果是这种情况,需要把myfile.py放在别的地方,而不是在package目录里面。在myfile.py使用一下语句就可以正常工作了:from package.moduleA import spam.
注:对于上面说的这两种情况,包目录(比如上面的package)必须存在于python的搜索路径下面(sys.path)。如果不存在,你将不能够使用包中的任何东西。
自从python2.6,模块的名称不在决定使用__name__属性,而是使用__packege__属性。这就是为什么我避免使用__name__这么明确的名称来代表一个模块的名称。自从python2.6,一个模块的名称是由__package__+'.'+__name__来确定的,如果__packege__是None的话,那么这个名称就是__name__了。
python相对包导入报“Attempted relative import in non-package”错误的更多相关文章
- Python 相对导入attempted relative import beyond top-level package
ValueError: attempted relative import beyond top-level package 假设有如下层次包目录 project/ __init__.py mypac ...
- Python导入自定义类时显示错误:attempted relative import beyond top-level package
显示这个错误可能有两个原因: 1.文件夹中没有包含__init__.py文件,该文件可以为空,但必须存在该文件. 2.把该文件当成主函数入口,该文件所在文件夹不能被解释器视作package,所以可能导 ...
- 相对导入中Attempted relative import in non-package问题
这一篇应该是解释的比较清楚: http://stackoverflow.com/questions/14664313/attempted-relative-import-in-non-package- ...
- ValueError: attempted relative import beyond top-level package
python 项目 在pycharm中, 在某个文件夹下: 右键--> mark directory as --> source root 如何在python脚本或者shell中 用代码实 ...
- Python ValueError: Attempted relative import in non-package Relative import相对引用 错误
包含相对路径import的python脚本不能直接运行,只能作为module被引用. 例如 from . import mod1 有这样代码的文件只能最为moulule为不能直接运行.相对路径就是相对 ...
- python:Attempted relative import in non-package
problem:Attempted relative import in non-package 所谓相对路径其实就是相对于当前module的路径,但如果直接执行脚本,这个module的name就是“ ...
- Python工程:ImportError: attempted relative import with no known parent package
Python工程:ImportError: attempted relative import with no known parent package 解决方法: 1.对每个目录创建的时候都选择创建 ...
- 执行代码出现ImportError:attempted relative import with no known parent package
前言 在这篇文章中,我将会解析 ImportError: attempted relative import with no known parent package 这个异常的原因.当你在运行的py ...
- ValueError: Attempted relative import in non-package
执行:python deom/scripts/populate.py ValueError: Attempted relative import in non-package solve:python ...
随机推荐
- 阿里分布式开源框架DUBBO 入门+ 进阶+ 项目实战视频教程
史诗级Java/JavaWeb学习资源免费分享 欢迎关注我的微信公众号:"Java面试通关手册"(坚持原创,分享各种Java学习资源,面试题,优质文章,以及企业级Java实战项目回 ...
- 我的Apache又挂了之apache错误:server's fully qualified domain name, using 127.0.0.1. Set the 'ServerName'
表示物理机装Apache然后有时候关机会忘了关闭Apache然后长此以往会导致各种Apache起不来的缘故,上一次已经出现过一次.今天又出现了 再次记录一下解决的方法. 1.查看错误日志 /var/l ...
- s3c6410下移植sqlite3.7.8
http://blog.chinaunix.NET/uid-30441-id-2133838.html 1.下载源代码http://www.sqlite.org/download.html 2.tar ...
- shell读取文件的每一行内容并输出【转】
写法一: #!/bin/bash while read line do echo $line done < file(待读取的文件) 写法二: #!/bin/bash cat file(待读取的 ...
- Windows 和Linux 误删除后的恢复
ext文件系统上删除文件,可以恢复:extundelete; windows 恢复删除文件: final data v2.0汉化版 和 easyrecovery
- NOIP填坑计划
斗地主 华容道 开车旅行 疫情控制 飞扬的小鸟 Mayan游戏 天天爱跑步
- Spring学习-理解IOC和依赖注入
最近刚买了一本介绍ssm框架的书,里面主要对Mybatis.spring.springmvc和redis做了很多的讲解,个人觉得虽然有的内容我看不懂,但是整体上还是不错的.最近正在学习中,一边学习一边 ...
- 小程序canvasu真机上数据图片不能使用
canvas遇到的坑 1.文字换行 2.真机不能使用网络数据图片(真坑) 点击显示效果我就不写了,你们可以自己加一下 全部代码贴出来 css #preview { width: 100%; heigh ...
- 总结开发ERP软件应遵循的一些基本原则
总结一下做管理软件,有哪些项是经过检验的条款,必须遵守的. 界面篇 1 要保存用户的偏号(profile/favourite). ASP.NET 2.0引入此功能,当用户修改默认的控件的属性时,框架 ...
- lr关联抓有相同左右边界的动态值
怎样抓取有相同左右边界的动态value? 怎样抓取有相同左右边界的动态value?例如: stateID="d7lg0ehmjkkm6uin3s4boei7oq"> stat ...