第十亿次相对进口
我来过这里:
以及大量的我没有复制的网址,有些网址是在其他网站上,有些在我以为我很快就能找到解决方案。
永远再次出现的问题是:对于Windows 7,32位Python 2.7.3,我该如何解决这个“试图在非包中导入相对导入”消息? 我在pep-0328上构建了一个完整的包装副本:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
我确实在适当的模块中创建了名为垃圾邮件和鸡蛋的函数。 自然,它不起作用。 答案显然是在我列出的第4个URL中,但这是我的所有校友。 我访问过的其中一个网址有这样的回应:
相对导入使用模块的名称属性来确定模块在程序包层次结构中的位置。 如果模块的名称不包含任何包信息(例如,它被设置为'main'),则无论模块在文件系统上的实际位置如何,相对导入都会被解析为模块是顶级模块。
上面的回应看起来很有希望,但这对我来说都是象形文字。 所以我的问题,我如何使Python不返回给我“试图在非包中的相对导入”? 有一个答案,涉及-m,据说。
有人可以告诉我为什么Python给出了这个错误信息,它是什么意思,非包装!,为什么以及如何定义一个'包', 准确的答案放在容易让幼儿园的人理解 。
编辑:导入是从控制台完成的。
脚本与模块
这是一个解释。 简短的版本是,直接运行Python文件和从其他地方导入该文件有很大的区别。 只知道文件所在的目录并不能确定Python认为它在哪个包中。此外,还取决于如何将文件加载到Python中(通过运行或导入)。
加载Python文件有两种方法:作为顶级脚本或作为模块。 如果直接执行它,则会将文件作为顶级脚本加载,例如在命令行中键入python myfile.py
。 如果您执行python -m myfile
,则会将其作为模块加载,或者当某个import
语句被加载到某个其他文件中时加载它。 一次只能有一个顶级脚本; 顶层脚本是您开始启动的Python文件。
命名
当一个文件被加载时,它会被赋予一个名称(存储在__name__
属性中)。 如果它作为顶级脚本加载,则其名称为__main__
。 如果它是作为一个模块加载的,它的名称就是文件名,它的前面是它所包含的任何软件包/子包的名称,用点分隔。
例如在你的例子中:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
如果你导入了moduleX
(注:导入,不能直接执行),它的名字就是package.subpackage1.moduleX
。 如果你导入了moduleA
,它的名字就是package.moduleA
。 但是,如果您直接从命令行运行moduleX
,则它的名称将改为__main__
,并且如果moduleA
直接运行moduleA
,则其名称将为__main__
。 当一个模块作为顶级脚本运行时,它将失去它的正常名称,而它的名字是__main__
。
不通过其包含的包访问模块
有一个额外的皱纹:模块的名称取决于它是从目录中“直接”导入,还是通过包导入。 如果您在目录中运行Python,这只会有所不同,并尝试在同一目录(或其子目录)中导入文件。 举例来说,如果你开始在目录中的Python解释器package/subpackage1
然后做import moduleX
,名moduleX
将只是moduleX
,而不是package.subpackage1.moduleX
。 这是因为Python在启动时将当前目录添加到其搜索路径中; 如果它在当前目录中找到要导入的模块,则它不会知道该目录是包的一部分,并且包信息不会成为模块名称的一部分。
一种特殊情况是,如果您以交互方式运行解释器(例如,只需键入python
并开始输入Python代码即可)。 在这种情况下,该交互式会话的名称是__main__
。
现在,对于你的错误信息来说,这是至关重要的: 如果一个模块的名字没有点,它就不会被认为是包的一部分 。 文件实际在磁盘上的位置并不重要。 重要的是它的名字,它的名字取决于你如何加载它。
现在看看你的问题中包含的报价:
相对导入使用模块的名称属性来确定模块在程序包层次结构中的位置。 如果模块的名称不包含任何包信息(例如,它被设置为'main'),则无论模块在文件系统上的实际位置如何,相对导入都会被解析为模块是顶级模块。
相对导入...
相对导入使用模块的名称来确定它在包中的位置。 当你使用像from .. import foo
这样的相对导入时,这些点表示要在包层次结构中增加一些级别。 例如,如果你当前模块的名字是package.subpackage1.moduleX
,那么..moduleA
意味着package.moduleA
。 对于from .. import
到工作,模块的名称必须至少与import
语句中的点数一样多。
......只是在包装中相对而言
但是,如果您的模块名称是__main__
,则不会将其视为包中。 它的名字没有点,因此你不能在其中使用from .. import
语句。 如果你尝试这样做,你会得到“非包装中的相对导入”错误。
脚本无法导入相对
你可能做的是你试图从命令行运行moduleX
之类的东西。 当你这样做时,它的名字被设置为__main__
,这意味着它内部的相对导入将会失败,因为它的名字没有显示它在一个包中。 请注意,如果您从模块所在的同一目录运行Python,然后尝试导入该模块,也会发生这种情况,因为如上所述,Python会在当前目录中“太早”地发现模块而未意识到它是包的一部分。
另外请记住,当您运行交互式解释器时,该交互式会话的“名称”始终为__main__
。 因此, 您不能直接从交互式会话进行相关导入 。 相对导入仅用于模块文件中。
两种解决方案
如果你真的想直接运行moduleX
,但你仍然希望它被认为是包的一部分,你可以做python -m package.subpackage.moduleX
。 -m
告诉Python将其作为模块加载,而不是作为顶级脚本。
或者你也许并不想运行moduleX
,你只是想运行一些其他脚本,比如myfile.py
,它使用moduleX
函数。 如果是这样的话,把myfile.py
放到myfile.py
地方 - 不要放在package
目录中 - 然后运行它。 如果在myfile.py
执行诸如from package.moduleA import spam
,它将正常工作。
笔记
对于这两种解决方案,包目录( package
在你的例子)必须从Python模块搜索路径(访问sys.path
)。 如果不是,那么您将无法可靠地在包装中使用任何东西。
从Python 2.6开始,用于包解析目的的模块“名称”不仅由__name__
属性决定,还由__package__
属性决定。 这就是为什么我避免使用显式符号__name__
来引用模块的“名称”。 从Python 2.6开始,模块的“名称”实际上是__package__ + '.' + __name__
__package__ + '.' + __name__
,或者如果__package__
是None
,则只是__name__
。)
这在python中确实是一个问题。 混淆的根源在于人们错误地将相对进口视为不是相对的进口。
例如,当你在faa.py中写入时:
from .. import foo
这只有在faa.y在执行过程中被python识别并加载作为包的一部分时才有意义。 在这种情况下,faa.py的模块名称就是some_packagename.faa。 如果仅仅因为它在当前目录中而被加载文件,那么当运行python时,它的名称将不会引用任何包,并且最终相对导入会失败。
引用当前目录中的模块的简单解决方案是使用这个:
if __package__ is None or __package__ == '':
#uses current directory visibility
import foo
else:
#uses current package visibility
from . import foo
以下是我不推荐的一种解决方案,但在某些情况下模块根本不生成可能会有用:
import os
import sys
parent_dir_name = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(parent_dir_name + "/your_dir")
import your_script
your_script.a_function()
链接地址: http://www.djcxy.com/p/55065.html
上一篇: Relative imports for the billionth time
下一篇: Check if a Python list item contains a string inside another string