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']
答案 0 :(得分:6)
通常应避免使用循环导入,另请参阅this answer to a related question或this 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
中的模块,那么类似的东西仍然会在后台发生。不同之处在于您获得的结构较不扁平(因为导入不再仅从包中启动)。因此,module1
和module2
都会“启动”并且您将获得相应的初始化打印。
要使其正常工作,您可以在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 .package
或from app.package
。