首页 > Python > 如何让 Python 不返回给我“尝试在非包中相对导入”?

如何让 Python 不返回给我“尝试在非包中相对导入”?

上一篇 下一篇

我来过这里:

  • http://www.python.org/dev/peps/pep-0328/
  • http://docs.python.org/2/tutorial/modules.html#packages
  • Python 包:相对导入
  • Python 相对导入示例代码不起作用
  • Python 2.5 中的相对导入
  • Python 中的相对导入
  • Python:禁用相对导入

还有很多我没有复制的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.pyimport

命名

加载文件时,会为其指定一个名称(存储在其属性中)。__name__

  • 如果它是作为顶级脚本加载的,则其名称为 。__main__
  • 如果它是作为模块加载的,则其名称为 [ 文件名,前面是它所属的任何包/子包的名称,用点分隔 ],例如 。package.subpackage1.moduleX

但请注意,如果您使用类似 的东西从 shell 命令行加载为模块,则仍将是 。moduleXpython -m package.subpackage1.moduleX__name____main__

例如,在您的示例中:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

如果导入(注意:导入,而不是直接执行),则其名称将为 。如果导入 ,则其名称为 。但是,如果直接从命令行运行,则其名称将为 ,如果直接从命令行运行,则其名称将为 。当模块作为顶级脚本运行时,它将失去其正常名称,而是其名称为 。moduleXpackage.subpackage1.moduleXmoduleApackage.moduleAmoduleX__main__moduleA__main____main__

不通过模块包含包访问模块

还有一个额外的问题:模块的名称取决于它是从它所在的目录中“直接”导入还是通过包导入。这只有在您在目录中运行 Python 并尝试在同一目录(或其子目录)中导入文件时才有区别。例如,如果你在目录中启动 Python 解释器,然后执行 ,则 的名称将只是 ,而不是 。这是因为当以交互方式输入解释器时,Python 会将当前目录添加到其搜索路径中;如果在当前目录中找到要导入的模块,它将不知道该目录是包的一部分,并且包信息不会成为模块名称的一部分。package/subpackage1import moduleXmoduleXmoduleXpackage.subpackage1.moduleX

一种特殊情况是,如果您以交互方式运行解释器(例如,只需键入并开始动态输入 Python 代码)。在这种情况下,该交互式会话的名称为 。python__main__

现在,对于您的错误消息至关重要:如果模块的名称没有点,则不将其视为包的一部分。文件在磁盘上的实际位置并不重要。重要的是它的名字是什么,它的名字取决于你如何加载它。

现在看看你在问题中包含的报价:

相对导入使用模块的 name 属性来确定该模块在包层次结构中的位置。如果模块的名称不包含任何包信息(例如,它设置为“main”),则相对导入将解析为模块是顶级模块,而不管模块在文件系统上的实际位置如何。

相对进口…

相对导入使用模块的名称来确定它在包中的位置。当您使用相对导入(如 )时,点表示在包层次结构中提升一定数量的级别。例如,如果当前模块的名称是 ,则表示 。要使 正常工作,模块的名称必须至少具有与语句中一样多的点。from .. import foopackage.subpackage1.moduleX..moduleApackage.moduleAfrom .. importimport

…在包中仅是相对的

但是,如果模块的名称是 ,则不将其视为在包中。它的名称没有点,因此您不能在其中使用语句。如果您尝试这样做,您将收到“非包中的相对导入”错误。__main__from .. import

脚本无法导入相对

您可能所做的是尝试从命令行运行或类似操作。执行此操作时,其名称设置为 ,这意味着其中的相对导入将失败,因为其名称不会显示它在包中。请注意,如果您从模块所在的同一目录运行 Python,然后尝试导入该模块,也会发生这种情况,因为如上所述,Python 会“过早”地在当前目录中找到该模块,而没有意识到它是包的一部分。moduleX__main__

另请记住,当您运行交互式解释器时,该交互式会话的“名称”始终为 。因此,您无法直接从交互式会话执行相对导入。相对导入仅用于模块文件。__main__

两种解决方案:

  1. 如果您确实想直接运行,但仍然希望将其视为包的一部分,则可以执行。它告诉 Python 将其作为模块加载,而不是作为顶级脚本加载。moduleXpython -m package.subpackage1.moduleX-m
  2. 或者也许你其实并不想运行,你只是想运行一些其他的脚本,比如说,里面使用函数。如果是这种情况,请放在其他地方而不是在目录中 – 并运行它。如果你在里面做类似的事情,它会正常工作。moduleXmyfile.pymoduleXmyfile.pypackagemyfile.pyfrom package.moduleA import spam

笔记

  • 对于其中任一解决方案,包目录(在您的示例中)必须可从 Python 模块搜索路径 () 访问。如果不是,您将根本无法可靠地使用包中的任何内容。packagesys.path
  • 从 Python 2.6 开始,用于包解析目的的模块“名称”不仅由其属性决定,还由属性决定。这就是为什么我避免使用显式符号来引用模块的“名称”。从 Python 2.6 开始,模块的“名称”实际上是 ,或者只是如果 是。__name____package____name____package__ + '.' + __name____name____package__None

分割线

网友回答:

外语中有太多太长的安韦尔。所以我会尽量简短。

如果你写,与你的想法相反,不会从当前目录导入,而是从包的顶层导入!如果.py文件作为脚本运行,它根本不知道顶层在哪里,因此拒绝工作。from . import modulemodule

如果你从上面的目录开始这样,那么python知道顶层在哪里。这与Java非常相似:py -m package.modulepackagejava -cp bin_directory package.class

模板简介:该模板名称为【如何让 Python 不返回给我“尝试在非包中相对导入”?】,大小是暂无信息,文档格式为.编程语言,推荐使用Sublime/Dreamweaver/HBuilder打开,作品中的图片,文字等数据均可修改,图片请在作品中选中图片替换即可,文字修改直接点击文字修改即可,您也可以新增或修改作品中的内容,该模板来自用户分享,如有侵权行为请联系网站客服处理。欢迎来懒人模板【Python】栏目查找您需要的精美模板。

相关搜索
  • 下载密码 lanrenmb
  • 下载次数 217次
  • 使用软件 Sublime/Dreamweaver/HBuilder
  • 文件格式 编程语言
  • 文件大小 暂无信息
  • 上传时间 03-02
  • 作者 网友投稿
  • 肖像权 人物画像及字体仅供参考
栏目分类 更多 >
热门推荐 更多 >
微信文章 微信图片 微信模板 企业网站 自适应 响应式 微信素材 html5 单页式简历模板 微信公众平台
您可能会喜欢的其他模板