Python 3中的相对导入问题

war*_*iuc 12 python importerror python-3.x

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
Run Code Online (Sandbox Code Playgroud)

我明白了:

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$ 
Run Code Online (Sandbox Code Playgroud)

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 module2module1工作正常,但from . import module1module2工作中...

更新:

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

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']
Run Code Online (Sandbox Code Playgroud)

pok*_*oke 6

通常应该避免循环导入,参见相关问题的这个答案,或者关于effbot.org的这篇文章.

在这种情况下,问题是,你导入from .其中,.是当前包.所以你的所有from . import X进口都要通过包装__init__.py.

如果您明确地导入模块__init__.py并给它们另一个名称(并调整其他导入以使用这些名称),您可以使问题更加明显:

print('Init package1')
from . import module1 as m1
from . import module2 as m2
Run Code Online (Sandbox Code Playgroud)

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

如果你没有明确地导入__init__.py类似的东西仍然在后台发生.不同之处在于您获得的结构较不扁平(因为导入不再仅从包中启动).这样既module1module2得到"开始",你会得到相应的初始化打印.

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

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

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

编辑

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


Len*_*bro 6

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