我来过这里:
还有很多我没有复制的URL,有些在SO上,有些在其他网站上,当我认为我会很快找到解决方案时。
永远反复出现的问题是:如何解决此“尝试在非包中相对导入”消息?
ImportError: attempted relative import with no known parent package
我在 pep-0328 上构建了该软件包的精确复制品:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleY.py
subpackage2/
__init__.py
moduleZ.py
moduleA.py
导入是从控制台完成的。
我确实在适当的模块中制作了名为垃圾邮件和鸡蛋的函数。自然,它没有用。答案显然在我列出的第 4 个 URL 中,但这对我来说都是校友。在我访问的其中一个 URL 上有这样的响应:
相对导入使用模块的 name 属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它设置为“main”),则相对导入将解析为模块是顶级模块,而不管模块在文件系统上的实际位置如何。
上面的回应看起来很有希望,但对我来说都是象形文字。所以我的问题,如何让 Python 不返回给我“尝试在非包中相对导入”?据说有一个涉及 -m 的答案。
有人可以告诉我为什么Python会给出该错误消息,“非包”是什么意思,为什么以及如何定义“包”,以及准确的答案,用足够容易让幼儿园的孩子理解的术语。
网友回答:
这确实是python中的一个问题。混淆的根源是人们错误地将相对导入视为路径相对,而路径相对不是。
例如,当您在 faa.py 中编写时:
from .. import foo
只有当 python 在执行过程中将 faa.py 识别并加载为包的一部分时,这才有意义。在这种情况下,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
网友回答:
脚本与模块
这里有一个解释。简而言之,直接运行Python文件和从其他地方导入该文件之间存在很大差异。仅仅知道文件在哪个目录中并不能确定 Python 认为它位于哪个包中。此外,这取决于如何将文件加载到 Python 中(通过运行或导入)。
有两种方法可以加载 Python 文件:作为顶级脚本或作为
模块。如果直接执行文件,例如通过在命令行上键入,则会将文件作为顶级脚本加载。当在某个其他文件中遇到语句时,它将作为模块加载。一次只能有一个顶级脚本;顶级脚本是您运行以启动操作的 Python 文件。python myfile.py
import
命名
加载文件时,会为其指定一个名称(存储在其属性中)。__name__
__main__
package.subpackage1.moduleX
但请注意,如果您使用类似 的东西从 shell 命令行加载为模块,则仍将是 。moduleX
python -m package.subpackage1.moduleX
__name__
__main__
例如,在您的示例中:
package/
__init__.py
subpackage1/
__init__.py
moduleX.py
moduleA.py
如果导入(注意:导入,而不是直接执行),则其名称将为 。如果导入 ,则其名称为 。但是,如果直接从命令行运行,则其名称将为 ,如果直接从命令行运行,则其名称将为 。当模块作为顶级脚本运行时,它将失去其正常名称,而是其名称为 。moduleX
package.subpackage1.moduleX
moduleA
package.moduleA
moduleX
__main__
moduleA
__main__
__main__
不通过模块包含包访问模块
还有一个额外的问题:模块的名称取决于它是从它所在的目录中“直接”导入还是通过包导入。这只有在您在目录中运行 Python 并尝试在同一目录(或其子目录)中导入文件时才有区别。例如,如果你在目录中启动 Python 解释器,然后执行 ,则 的名称将只是 ,而不是 。这是因为当以交互方式输入解释器时,Python 会将当前目录添加到其搜索路径中;如果在当前目录中找到要导入的模块,它将不知道该目录是包的一部分,并且包信息不会成为模块名称的一部分。package/subpackage1
import moduleX
moduleX
moduleX
package.subpackage1.moduleX
一种特殊情况是,如果您以交互方式运行解释器(例如,只需键入并开始动态输入 Python 代码)。在这种情况下,该交互式会话的名称为 。python
__main__
现在,对于您的错误消息至关重要:如果模块的名称没有点,则不将其视为包的一部分。文件在磁盘上的实际位置并不重要。重要的是它的名字是什么,它的名字取决于你如何加载它。
现在看看你在问题中包含的报价:
相对导入使用模块的 name 属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它设置为“main”),则相对导入将解析为模块是顶级模块,而不管模块在文件系统上的实际位置如何。
相对进口…
相对导入使用模块的名称来确定它在包中的位置。当您使用相对导入(如 )时,点表示在包层次结构中提升一定数量的级别。例如,如果当前模块的名称是 ,则表示 。要使 正常工作,模块的名称必须至少具有与语句中一样多的点。from .. import foo
package.subpackage1.moduleX
..moduleA
package.moduleA
from .. import
import
…在包中仅是相对的
但是,如果模块的名称是 ,则不将其视为在包中。它的名称没有点,因此您不能在其中使用语句。如果您尝试这样做,您将收到“非包中的相对导入”错误。__main__
from .. import
脚本无法导入相对
您可能所做的是尝试从命令行运行或类似操作。执行此操作时,其名称设置为 ,这意味着其中的相对导入将失败,因为其名称不会显示它在包中。请注意,如果您从模块所在的同一目录运行 Python,然后尝试导入该模块,也会发生这种情况,因为如上所述,Python 会“过早”地在当前目录中找到该模块,而没有意识到它是包的一部分。moduleX
__main__
另请记住,当您运行交互式解释器时,该交互式会话的“名称”始终为 。因此,您无法直接从交互式会话执行相对导入。相对导入仅用于模块文件。__main__
两种解决方案:
moduleX
python -m package.subpackage1.moduleX
-m
moduleX
myfile.py
moduleX
myfile.py
package
myfile.py
from package.moduleA import spam
笔记
package
sys.path
__name__
__package__
__name__
__package__ + '.' + __name__
__name__
__package__
None
网友回答:
外语中有太多太长的安韦尔。所以我会尽量简短。
如果你写,与你的想法相反,不会从当前目录导入,而是从包的顶层导入!如果.py文件作为脚本运行,它根本不知道顶层在哪里,因此拒绝工作。from . import module
module
如果你从上面的目录开始这样,那么python知道顶层在哪里。这与Java非常相似:py -m package.module
package
java -cp bin_directory package.class
模板简介:该模板名称为【如何让 Python 不返回给我“尝试在非包中相对导入”?】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【Python】栏目查找您需要的精美模板。