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']
更好的解决方案是将package1放在自己独立的包中。当然然后它无法导入package2,但如果它可以重用,那么为什么呢?
一般应避免循环进口,另见 这是对相关问题的回答, 要么 这篇关于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
。
您的更新模拟绝对导入的作用: import package1.module1
如果你这样做的话 module1
被进口。如果您想使用动态父包名称,则导入 module1
在里面 module2.py
:
import importlib
module1 = importlib.import_module('.module1', __package__)
我需要循环进口。 module1中的一个函数断言其中一个函数
parameter是在module2中定义的类的实例,反之亦然。
您可以将一个类移动到一个单独的模块以解决循环依赖关系,或者如果您不想使用绝对导入,则在函数级别进行导入。
.
├── start.py
# from package1 import module1
└── package1
├── __init__.py
# print("Init package1")
# from . import module1, module2
├── c1.py
# print("Init package1.c1")
# class C1:
# pass
├── module1.py
# print("Init package1.module1")
# from .c1 import C1
# from .module2 import C2
└── module2.py
# print("Init package1.module2")
# from .c1 import C1
# class C2:
# pass
# def f():
# from .module1 import C1
产量
Init package1
Init package1.module1
Init package1.c1
Init package1.module2
另一种选择可能比重构更简单 c1.py
是合并 module{1,2}.py
变成一个单一的 common.py
。 module{1,2}.py
从中导入 common
在这种情况下。
module2.py
import module1
也工作。
接受的答案 Python中的循环导入依赖项 提出一个好点:
如果a取决于c和c取决于a,那么它们实际上不是同一个单位吗?
你应该真正检查为什么你将a和c分成两个包,因为要么你有一些代码你应该拆分成另一个包(使它们都依赖于那个新的包,而不是彼此),或者你应该合并它们成一个包。
- Lasse V. Karlsen
也许您应该考虑将它们放在同一个模块中。 :)
我今天遇到了同样的问题,看来这确实在python3.4中被破坏了,但是在python3.5中运行。
该 更新日志 有一个条目:
现在支持涉及相对进口的循环进口。 (由Brett Cannon和Antoine Pitrou提供 BPO-17636)。
通过bug报告,似乎这不是一个固定的buf,以及导入工作方式的新功能。参考 戳上面的答案,他表明了这一点 from . import foo
意味着加载 __init__.py
得到 foo
从它(可能来自隐式加载的子模块列表)。从python3.5开始, from . import foo
也会这样做,但如果 foo
作为属性不可用,它将回退到查看已加载模块的列表(sys.modules
)看它是否已经存在,这解决了这个特殊情况。不过,我并不是100%确定我是否正确地介绍了它的工作原理。
确保你的 package1
是一个文件夹。在中创建一个类 __init__.py
- 说 class1
。将您的逻辑包含在一个方法下 class1
- 说 method1
。
现在,编写以下代码 -
from .package1 import class1
class1.method1()
这是我解决它的方式。总而言之,您的根目录是 .
写你的 import
声明使用 .
符号,例如 from .package
要么 from app.package
。