Python导入失败。相对导入,包识别,__ init__.py,__ package__,__ all__

时间:2016-10-05 14:16:05

标签: python import python-2.x

我一直在阅读很多帖子,与这个问题相关的PEP文章大约有4个,但是没有一个在某些方面给出了明确的想法,我仍然无法做到相对进口。

事实上,我的主包的内容根本没有列出。

REEDITION。我修改了所有帖子,它太复杂了,问题也很多。

C:/test/我有这个包:

Package/ (FOLDER 2)
    __init__.py
    moduleA.py
    moduleB.py
  • moduleA导入moduleB,反之亦然。
  • __init__.py为空

我的流程:

  1. 我将C:/test/添加到sys.path
  2. import Package(WORKS)
  3. dir(Package) 不列出Package中的任何模块。
  4. 套餐是:<module ‘Package’ from C:/test/Package/_init_.py>
  5. __file__是Package
  6. 下的init文件
  7. __name__Package
  8. __package__ 是一个空字符串
  9. __path__C:/test/Package
  10. 测试1 - 版本1: 在moduleA我有from Package import moduleB

    我明白了:

    >>> import Package.moduleA
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "C:/test\Package\moduleA.py", line
        from Package import moduleB
      File "C:/test\Package\moduleB.py", line
        from Package import moduleA
    ImportError: cannot import name moduleA
    

    它不起作用,因为moduleA不属于Package。那么Package不被视为包裹?

    测试1 - 版本2: 在moduleA我有from . import moduleB

    不起作用,同样的错误

    测试1 - 版本3: 在moduleA我有import Package.moduleB

    有效。

    之后,运行:

    >>> dir(Package.moduleB)
    ['Package', '__builtins__', '__doc__', '__file__', '__name__', '__package__']
    >>> Package.moduleB.Package
    <module 'Package' from 'C:/prueba\Package\__init__.py'>
    >>> dir(Package)
    ['__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', 'moduleA', 'moduleB']
    

    现在,Package.moduleBPackage作为变量 令人惊讶的是,Package看起来像一个合适的包,并包含两个模块。

    事实上,现在可以在版本1和版本2中执行任何导入,因为现在moduleAmoduleB属于Package

    问题:

    1)为什么Package未被识别为包裹?是吗?它不应该包含所有子模块吗?

    2)为什么在import Package.moduleA内运行Package生成moduleA

    3)为什么运行import Package.moduleA会将moduleA添加到Package并且之前没有?

    4)空__init__.py个文件和NON空__init__.py文件是否会对此产生影响?

    5)定义包含__all__的{​​{1}}变量是否会在此处执行任何操作?

    6)如何使init文件加载两个子模块?我应该在['moduleA', 'moduleB']import Package.moduleA里面做什么?...我能不能像Package.moduleB或类似的那样做? (如果import .moduleA as moduleA的名称发生变化,该怎么办?)

    7)包变量上的空字符串是否会影响?如果我们希望它能够识别自己,我们应该更改它的内容...... Package应该与__package__相同,或者是PEP所说的内容。但这样做并不奏效:

    __name__

2 个答案:

答案 0 :(得分:1)

这是一个循环依赖问题。它与此question非常相似,但不同之处在于您尝试从包中导入模块,而不是从模块中导入类。在这种情况下,最好的解决方案是重新考虑您的代码,以便不需要循环依赖。将任何常用函数或类移出到包中的第三个模块。

担心__package__是一只红鲱鱼。当您的包成为正确的包时,python导入系统将适当地设置它。

问题是moduleAmoduleB只有在成功导入后才会放在package中。但是,由于moduleAmoduleB都处于导入状态,因此无法在package中看到对方。当您绕过相对导入机制时,绝对导入部分解决了问题。但是,如果您的模块在初始化期间需要彼此的部分,则程序将失败。

如果删除var = ...行,则以下代码可以使用。

package.moduleA

import package.moduleB
def func():
    return 1

package.moduleB

import package.moduleA
var = package.moduleA.func() # error, can't find moduleA

损坏的

的示例

package.moduleA

from . import moduleB
def depends_on_y():
    return moduleB.y()
def x():
    return "x"

package.moduleB

from . import moduleA
def depends_on_x():
    return moduleA.x()
def y():
    return "y"

将公共部件提取到包中的单独模块

中的示例

package.common

def x():
    return "x"
def y():
    return "y"

package.moduleA

from .common import y
def depends_on_y():
    return y()

package.moduleB

from .common import x
def depends_on_x():
    return x()

答案 1 :(得分:0)

这是一个Python错误,存在于3.5之前的Python版本中。请参阅issue 992389讨论的内容(多年)和issue 17636,其中解决了问题的常见情况。

在Python 3.5中进行修复后,在from . import moduleA包中的模块中显式相对导入(Package)会在放弃sys.modules之前检查Package.moduleA,然后放弃moduleA尚未提供Package。由于模块对象在开始加载之前已添加到sys.modules,但在加载完成之前未添加到Package.__dict__,这通常可以解决问题。

使用from package import *进行循环导入仍然存在问题,但在issue 23447(我为其提供了补丁)中,确定修复那个更加模糊的角落案例并不值得额外的代码复杂性。

循环进口通常是设计糟糕的表现。您可能要么将依赖于彼此的代码位重构为两个其他模块导入的单个实用程序模块,要么将两个单独的模块组合成一个单独的模块。