Python-相对导入十亿次
存在的问题是:在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
(请注意:imported
,未直接执行),则其名称为package.subpackage1.moduleX
。如果导入moduleA
,则名称为package.moduleA
。但是,如果直接从命令行运行 moduleX
,则名称为__main__
,如果直接从命令行运行moduleA
,则名称为__main__
。当模块作为顶级脚本运行时,它将失去其常规名称,而其名称改为__main__
。
不通过其包含的包访问模块
还有一个额外的问题:模块的名称取决于它是从其所在目录“直接”导入还是通过软件包导入。仅当你在目录中运行Python并尝试在该目录(或其子目录)中导入文件时,这才有所不同。例如,如果你在目录中启动Python解释器package/subpackage1
,然后执行do import moduleX
,则其名称moduleX将仅为moduleX
,而不是package.subpackage1.moduleX
。这是因为Python在启动时会将当前目录添加到其搜索路径中。如果它在当前目录中找到了要导入的模块,则不会知道该目录是软件包的一部分,并且软件包信息也不会成为模块名称的一部分。
一种特殊情况是,如果你以交互方式运行解释器(例如,只需键入python并开始即时输入Python代码)。在这种情况下,该交互式会话的名称为__main__
。
现在,这是你的错误消息的关键所在:如果模块的名称没有点,则不认为它是包的一部分。文件实际在磁盘上的哪个位置都没有关系。重要的是它的名称是什么,它的名称取决于你如何加载它。
现在查看你在问题中包含的报价:
相对导入使用模块的名称属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,将其设置为“ main
”),则相对导入的解析就好像该模块是顶级模块一样,无论该模块实际位于文件系统上的哪个位置。
相对进口…
相对导入使用模块的名称来确定它在包中的位置。当你使用类似的相对导入时from .. import foo
,点表示在软件包层次结构中增加了一定数量的级别。例如,如果你当前模块的名称是package.subpackage1.moduleX
,则..moduleA
表示package.moduleA
。为了使a from .. import
起作用,模块名称必须至少包含与import语句中一样多的点。
…只是相对的
但是,如果模块的名称为__main__
,则不认为它在软件包中。它的名称没有点,因此你不能from .. import
在其中使用语句。如果你尝试这样做,则会收到“非包中的相对导入”错误。
脚本无法导入相对
你可能要做的是尝试从命令行运行moduleX
等。当你执行此操作时,其名称设置为__main__
,这意味着其中的相对导入将失败,因为其名称不会显示它在软件包中。请注意,如果你从模块所在的同一目录中运行Python,然后尝试导入该模块,也会发生这种情况,因为如上所述,Python
会“过早”在当前目录中找到该模块,而没有意识到它是包装的一部分。
还请记住,当你运行交互式解释器时,该交互式会话的“名称”始终为__main__。因此,你不能直接从交互式会话进行相对导入。相对导入仅在模块文件中使用。
两种解决方案:
如果你确实确实想moduleX
直接运行,但是仍然希望将其视为软件包的一部分,则可以这样做python -m package.subpackage1.moduleX
。该命令-m告诉Python将其作为模块而不是顶级脚本进行加载。
也许你实际上并不想运行 moduleX
,而只想运行其他脚本,例如myfile.py
,该脚本使用 inside
的功能moduleX
。如果是这样的话,把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__
,或者只是__name__
如果__package__
是None
)。
以上是 Python-相对导入十亿次 的全部内容, 来源链接: utcz.com/qa/414831.html