Python 3中的相对导入问题

时间:2011-11-06 20:46:35

标签: python python-3.x importerror

Python导入让我发疯(我的python导入经验有时根本不符合成语'明确比隐含更好':():

[app]
    start.py
        from package1 import module1
    [package1]
        __init__.py
            print('Init package1')
        module1.py
            print('Init package1.module1')
            from . import module2
        module2.py
            print('Init package1.module2')
            import sys, pprint
            pprint.pprint(sys.modules)
            from . import module1

我明白了:

vic@ubuntu:~/Desktop/app2$ python3 start.py 
Init package1
Init package1.module1
Init package1.module2
{'__main__': <module '__main__' from 'start.py'>,
 ...
 'package1': <module 'package1' from '/home/vic/Desktop/app2/package1/__init__.py'>,
 'package1.module1': <module 'package1.module1' from '/home/vic/Desktop/app2/package1/module1.py'>,
 'package1.module2': <module 'package1.module2' from '/home/vic/Desktop/app2/package1/module2.py'>,
 ...
Traceback (most recent call last):
  File "start.py", line 3, in <module>
    from package1 import module1
  File "/home/vic/Desktop/app2/package1/module1.py", line 3, in <module>
    from . import module2
  File "/home/vic/Desktop/app2/package1/module2.py", line 5, in <module>
    from . import module1
ImportError: cannot import name module1
vic@ubuntu:~/Desktop/app2$ 

import package1.module1有效,但我想使用from . import module1,因为我想让package1可移植用于其他应用程序,这就是我想使用相对路径的原因。

我正在使用python 3。

我需要循环进口。 module1中的一个函数断言它的一个参数是在module2中定义的类的实例,反之亦然。

换句话说:

sys.modules包含'package1.module1': <module 'package1.module1' from '/home/vic/Desktop/app2/package1/module1.py'>。我希望以from . import module1的形式获得对它的引用,但它试图获取一个名称,而不是像import package1.module1那样的包(它工作正常)。我试过import .module1 as m1 - 但这是语法错误。

此外,from . import module2中的module1工作正常,但from . import module1中的module2无效...

更新

这个黑客有效(但我正在寻找'官方'方式):

print('Init package1.module2')

import sys, pprint
pprint.pprint(sys.modules)

#from . import module1
parent_module_name = __name__.rpartition('.')[0]
module1 = sys.modules[parent_module_name + '.module1']

7 个答案:

答案 0 :(得分:6)

通常应避免使用循环导入,另请参阅this answer to a related questionthis article on effbot.org

在这种情况下,问题是您导入from .其中.是当前包。因此,您的所有from . import X导入都会通过包__init__.py

如果您在__init__.py中明确导入模块并为其指定其他名称(并调整其他导入以使用这些名称),则可以使问题更加明显:

print('Init package1')
from . import module1 as m1
from . import module2 as m2

现在,当您在m1中导入start.py时,该软件包会首先初始化m1并进入from . import m2行。此时,m2中没有__init__.py已知,因此您会收到导入错误。如果您在__init__.py周围切换导入语句(首先加载m2),然后在m2中找到from . import m1行,由于与以前相同的原因而失败

如果你没有明确地导入__init__.py中的模块,那么类似的东西仍然会在后台发生。不同之处在于您获得的结构较不扁平(因为导入不再仅从包中启动)。因此,module1module2都会“启动”并且您将获得相应的初始化打印。

要使其正常工作,您可以在module2中进行绝对导入。这样你就可以避免包首先需要解决所有问题,并使其重用start.py的导入(因为它具有相同的导入路径)。

甚至更好,你完全摆脱了循环导入。如果您有循环引用,通常表明您的应用程序结构不太好。

(我希望我的解释没有任何意义,我已经很难写了,但总的想法应该很明确,我希望...)

修改

回应您的更新;您正在做的是使用完整的包名来获取对模块的引用。这与使其工作的第一个可能选项等效(但要复杂得多);使用与start.py中相同的导入路径进行绝对导入。

答案 1 :(得分:6)

更好的解决方案是将package1放在自己独立的软件包中。当然然后它无法导入package2,但如果它可以重复使用,那么为什么会这样呢?

答案 2 :(得分:2)

答案 3 :(得分:1)

module2.py
          import module1

也适用。

答案 4 :(得分:0)

Circular import dependency in Python接受的答案提出了一个很好的观点:

  

如果a取决于c和c取决于a,那么它们实际上不是同一个单位吗?

     

你应该仔细检查为什么你将a和c拆分成两个包,因为要么你有一些代码你应该拆分成另一个包(使它们都依赖于那个新的包,而不是彼此),或者你应该将它们合并到一个包中    - Lasse V. Karlsen♦

也许您应该考虑将它们放在同一个模块中。 :)

答案 5 :(得分:0)

今天我遇到了同样的问题,看起来这确实在python3.4中被破坏了,但是在python3.5中运行。

changelog有一个条目:

  

现在支持涉及相对进口的循环导入。 (由Brett Cannon和Antoine Pitrou在bpo-17636中提供)。

通过bug报告,似乎这不是一个固定的buf,以及导入工作方式的新功能。参考poke's answer above,他表明__init__.py表示从中加载foo并从中获取from . import foo(可能来自隐式加载的子模块列表)。从python3.5开始,foo也会这样做,但如果sys.modules不可用作属性,它将回退到查看已加载模块列表(java -jar metabase.jar )以查看如果它已经存在,那就解决了这个特殊情况。我不是100%确定我是否正确地介绍了它是如何工作的。

答案 6 :(得分:0)

确保您的package1是一个文件夹。在__init__.py中创建一个类 - 比如class1。将您的逻辑包含在class1下的方法中 - 说method1

现在,编写以下代码 -

from .package1 import class1
class1.method1()

这是我解决问题的方法。总而言之,您的根目录是.,因此请使用import标记来编写.语句,例如from .packagefrom app.package