当前位置: 首页 > 知识库问答 >
问题:

第十亿次相对进口

彭修筠
2023-03-14

我来过这里:

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

还有很多我没有复制的网址,有些在SO上,有些在其他站点上,当我以为我能很快找到解决方案的时候。

一个经常出现的问题是:在Windows7,32位Python 2.7.3中,如何解决“尝试在非包中进行相对导入”消息?我在PEP-0328上构建了一个包的精确副本:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
        moduleY.py
    subpackage2/
        __init__.py
        moduleZ.py
    moduleA.py

导入是从控制台完成的。

我确实在其适当的模块中制作了名为spam和eggs的函数。很自然,这并没有奏效。答案显然在我列出的第4个URL中,但对我来说都是校友。在我访问的一个URL上有这样的回应:

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

上面的回应看起来很有希望,但对我来说都是象形文字。所以我的问题,我如何使Python不返回给我“尝试的非包中的相对导入”?答案应该是-M。

有人能告诉我为什么Python会给出这个错误信息,“非包”是什么意思,为什么和如何定义“包”,以及用一个幼儿园的孩子都能理解的术语给出准确的答案。

共有2个答案

潘志国
2023-03-14

这确实是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
吴炎彬
2023-03-14

脚本与模块

这里有个解释。简而言之,直接运行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,它的名称将改为__main__。当模块作为顶级脚本运行时,它将失去正常的名称,而改为__main__

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

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

一种特殊情况是,如果您以交互方式运行解释器(例如,只需键入Python并立即输入Python代码)。在本例中,交互会话的名称为__main__

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

现在看看你的问题中包含的引语:

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

相对导入...

相对导入使用模块的名称来确定它在包中的位置。当您使用类似的相对导入时..import foo中,点表示在包层次结构中增加一些级别。例如,如果当前模块的名称是package.subpackage1.modulex,那么..modulea将意味着package.modulea。对于来自..的import要工作,模块名称的点必须至少与import语句中的点一样多。

...在一个包中只是相对的

但是,如果您的模块的名称是__main__,则不认为它在包中。它的名称没有点,因此不能从..中使用Import语句。如果尝试这样做,将得到“relative-import in non-package”错误。

脚本无法导入相对

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

还要记住,当您运行交互式解释器时,该交互式会话的“名称”始终是__main__。因此,您不能直接从交互式会话进行相对导入。相对导入仅用于模块文件内。

两种解决方案:

>

  • 如果您确实希望直接运行modulex,但仍然希望将其视为包的一部分,则可以执行python-m package.subpackage1.modulex-m告诉Python将其作为模块加载,而不是作为顶级脚本加载。

    或者您实际上并不想运行modulex,只是想运行其他脚本,例如myfile.py,它使用modulex中的函数。如果是这种情况,请将myfile.py放在其他地方--而不是package目录中--并运行它。如果在myfile.py中执行类似于from package.modulea import spam的操作,那么它将很好地工作。

    备注

    >

  • 对于这两种解决方案中的任何一种,必须可以从Python模块搜索路径(sys.path)访问包目录(在示例中为package)。如果不是,您将根本无法可靠地使用包中的任何内容。

    从Python 2.6开始,用于包解析目的的模块“名称”不仅由其__name__属性决定,而且还由__package__属性决定。这就是为什么我避免使用显式符号__name__来引用模块的“名称”。由于Python 2.6a模块的“名称”实际上是__package__+'.'+__name__,或者如果__package__none,则仅__name__。)

  •  类似资料:
    • 问题内容: 存在的问题是:在Windows 7、32位Python 2.7.3中,如何解决此“尝试以非软件包方式进行相对导入”消息?我在上构建了该软件包的精确副本: 导入是从控制台完成的。 我确实在相应的模块中创建了名为垃圾邮件和鸡蛋的函数。自然,它不起作用。答案显然是在我列出的第4个网址中,但对我来说都是校友。我访问的其中一个URL上有此响应: 相对导入使用模块的名称属性来确定该模块在包层次结构

    • 我来过这里: http://www.python.org/dev/peps/pep-0328/ http://docs.python.org/2/tutorial/modules.html#包 Python包:相对导入 Python相对导入示例代码不起作用 python 2.5中的相对导入 Python中的相对导入 Python:禁用相对导入 还有很多URL我没有复制,有些在SO上,有些在其他网站

    • 在前面的内容中我们看见两种类型的顶点变换。第一种类型的变换是改变对象的位置(平移、旋转)或者尺寸(放缩)。这些变换允许我们在 3D 世界中把一个对象放在任何位置。第二种类型的变换是透视投影变换,把在 3D 世界坐标系下的顶点投影到 2D 世界坐标系下(比如一个平面上)。一旦坐标变换为 2D 坐标,那么我们非常容易的就能将这些 2D 坐标映射到屏幕坐标系下,根据这些屏幕坐标系下的坐标以及其对应的拓扑

    • Hadoop查询引擎 一、Phoenix 贡献者::Salesforce 简介:这是一个Java中间层,可以让开发者在Apache HBase上执行SQL查询。Phoenix完全使用Java编写,代码位于GitHub上,并且提供了一个客户端可嵌入的JDBC驱动。 Phoenix查询引擎会将SQL查询转换为一个或多个HBase scan,并编排执行以生成标准的JDBC结果集。直接使用HBase AP

    • 在这一节中我们将使用鼠标来控制相机的方向,从而得我们的相机控制更加完善。相机根据其使用的场景不同而有不同的自由度。在本教程中我们将要实现的是与第一人称游戏中相似的相机控制(如枪战类游戏)。这意味着我们将可以使相机完成 360 度的旋转(绕着 Y 轴),这与我们的头部向左转向右转、身体转一整圈类似。除此之外我们也能使相机向上或者向下倾斜以获得更好的向上的或者向下的视野但是我们不能使之沿同一转向翘起一

    • 在之前的教程中我们学习了如果当相机不位于初始位置时,如何使得得场景中的物体正确的投影到屏幕上面,那么我们下一步就应该学着去控制这个相机,使得相机可以在场景中自由移动。我们可以用鼠标和键盘控制相机——鼠标控制视口方向,键盘控制相机的位置。这些都和第一人称视角相似,这一节我们主要来学习鼠标和键盘对相机的控制。 我们仍然使用上下左右四个方向键。记住,我们的相机的变换取决于相机的位置、target 向量和