Python中的循环(或循环)导入
如果两个模块相互导入,会发生什么情况Python中的循环(或循环)导入,python,circular-dependency,cyclic-reference,Python,Circular Dependency,Cyclic Reference,如果两个模块相互导入,会发生什么情况 一般来说,Python中的循环导入如何?去年对此进行了很好的讨论。它非常彻底地回答了你的问题 进口真的很简单。只要记住以下几点: $ python a.py a in b imported: False b in a in b imported: True a out b out a out “import”和“from xxx import yyy”是可执行语句。他们执行 当运行的程序到达该行时 如果模块不在sys.modules中,则导入将创建新模块
一般来说,Python中的循环导入如何?去年对此进行了很好的讨论。它非常彻底地回答了你的问题 进口真的很简单。只要记住以下几点:
$ python a.py
a in
b imported: False
b in
a in
b imported: True
a out
b out
a out
“import”和“from xxx import yyy”是可执行语句。他们执行
当运行的程序到达该行时
如果模块不在sys.modules中,则导入将创建新模块
输入sys.modules,然后执行模块中的代码。事实并非如此
将控制权返回到调用模块,直到执行完成
如果sys.modules中确实存在模块,则导入只返回该模块
模块是否已完成执行。这就是原因
循环导入可能返回部分为空的模块
最后,执行脚本在名为uuu main_uuu的模块中运行,导入
该脚本将以其自己的名称创建一个与之无关的新模块
__主要问题
把这些东西放在一起,你在导入时不应该有任何惊喜
模块
循环导入终止,但在模块初始化期间,需要小心不要使用循环导入的模块 考虑以下文件: a、 py: b、 py: 如果执行a.py,将得到以下结果:
$ python a.py
a in
b imported: False
b in
a in
b imported: True
a out
b out
a out
在第二次导入b.py时(在中的第二个a中),Python解释器不会再次导入b
,因为它已经存在于模块dict中
如果在模块初始化期间尝试从a
访问b.x
,您将获得AttributeError
将以下行附加到a.py
:
print b.x
from src.main import Foo
class SpecificException(Exception):
def __init__(self, cause: Foo):
self.cause = cause
def __str__(self):
return f'Expected 3 but got {self.cause.attrib}.'
然后,输出为:
$ python a.py
a in
b imported: False
b in
a in
b imported: True
a out
Traceback (most recent call last):
File "a.py", line 4, in <module>
import b
File "/home/shlomme/tmp/x/b.py", line 2, in <module>
import a
File "/home/shlomme/tmp/x/a.py", line 7, in <module>
print b.x
AttributeError: 'module' object has no attribute 'x'
$python a.py
a在
b:错
b英寸
a在
b:是的
出局
回溯(最近一次呼叫最后一次):
文件“a.py”,第4行,在
进口b
文件“/home/shlomme/tmp/x/b.py”,第2行,在
导入
文件“/home/shlomme/tmp/x/a.py”,第7行,在
打印b.x
AttributeError:“模块”对象没有属性“x”
这是因为模块是在导入时执行的,在访问b.x
时,行x=3
尚未执行,这只会发生在b out
之后,如果执行导入foo
(内部bar.py
)和导入bar
(内部foo.py
),则工作正常。当任何东西实际运行时,这两个模块都将被完全加载,并且将具有彼此的引用
问题是当您从foo导入abc
(内部bar.py
)和从bar导入xyz(内部foo.py
)执行操作时。因为现在每个模块都要求在导入之前已经导入另一个模块(这样我们导入的名称就存在了)。我在这里得到了一个让我印象深刻的示例
foo.py
import bar
class gX(object):
g = 10
from foo import gX
o = gX()
import foo
import bar
print "all done"
import a
print("This is from module b")
from b import B
class A:
@staticmethod
def save_result(result):
print('save the result')
@staticmethod
def do_something_a_ish(param):
A.save_result(A.use_param_like_a_would(param))
@staticmethod
def do_something_related_to_b(param):
B.do_something_b_ish(param)
from a import A
class B:
@staticmethod
def do_something_b_ish(param):
A.save_result(B.use_param_like_b_would(param))
def save_result(result):
print('save the result')
from b import B
from c import save_result
class A:
@staticmethod
def do_something_a_ish(param):
A.save_result(A.use_param_like_a_would(param))
@staticmethod
def do_something_related_to_b(param):
B.do_something_b_ish(param)
from c import save_result
class B:
@staticmethod
def do_something_b_ish(param):
save_result(B.use_param_like_b_would(param))
bar.py
import bar
class gX(object):
g = 10
from foo import gX
o = gX()
import foo
import bar
print "all done"
import a
print("This is from module b")
from b import B
class A:
@staticmethod
def save_result(result):
print('save the result')
@staticmethod
def do_something_a_ish(param):
A.save_result(A.use_param_like_a_would(param))
@staticmethod
def do_something_related_to_b(param):
B.do_something_b_ish(param)
from a import A
class B:
@staticmethod
def do_something_b_ish(param):
A.save_result(B.use_param_like_b_would(param))
def save_result(result):
print('save the result')
from b import B
from c import save_result
class A:
@staticmethod
def do_something_a_ish(param):
A.save_result(A.use_param_like_a_would(param))
@staticmethod
def do_something_related_to_b(param):
B.do_something_b_ish(param)
from c import save_result
class B:
@staticmethod
def do_something_b_ish(param):
save_result(B.use_param_like_b_would(param))
main.py
import bar
class gX(object):
g = 10
from foo import gX
o = gX()
import foo
import bar
print "all done"
import a
print("This is from module b")
from b import B
class A:
@staticmethod
def save_result(result):
print('save the result')
@staticmethod
def do_something_a_ish(param):
A.save_result(A.use_param_like_a_would(param))
@staticmethod
def do_something_related_to_b(param):
B.do_something_b_ish(param)
from a import A
class B:
@staticmethod
def do_something_b_ish(param):
A.save_result(B.use_param_like_b_would(param))
def save_result(result):
print('save the result')
from b import B
from c import save_result
class A:
@staticmethod
def do_something_a_ish(param):
A.save_result(A.use_param_like_a_would(param))
@staticmethod
def do_something_related_to_b(param):
B.do_something_b_ish(param)
from c import save_result
class B:
@staticmethod
def do_something_b_ish(param):
save_result(B.use_param_like_b_would(param))
在命令行:$python main.py
Traceback (most recent call last):
File "m.py", line 1, in <module>
import foo
File "/home/xolve/foo.py", line 1, in <module>
import bar
File "/home/xolve/bar.py", line 1, in <module>
from foo import gX
ImportError: cannot import name gX
回溯(最近一次呼叫最后一次):
文件“m.py”,第1行,在
进口食品
文件“/home/xolve/foo.py”,第1行,在
进口栏
文件“/home/xolve/bar.py”,第1行,在
来自foo import gX
导入错误:无法导入名称gX
好的,我想我有一个非常酷的解决方案。
假设您有文件a
和文件b
。
您想在模块a
中使用文件b
中的def
或class
,但您还需要在文件b
中的定义或类中使用的def
、class
或文件a
中的变量。
您可以做的是,在文件a
的底部,在调用文件a
中文件b
中所需的函数或类之后,但在从文件b
中调用文件a
所需的函数或类之前,说import b
然后,这里是关键部分,在文件b
中所有需要def
或文件a
中的class
(我们称之为class
)的定义或类中,您可以说是导入类中的
这是因为您可以导入文件b
,而无需Python执行文件b
中的任何导入语句,因此可以避免任何循环导入
例如:
文件a:
文件b:
瞧。正如其他答案所描述的,这种模式在python中是可以接受的:
def dostuff(self):
from foo import bar
...
try:
from images.serializers import SimplifiedImageSerializer
except ImportError:
import sys
SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer']
这将避免在其他模块导入文件时执行import语句。只有当存在逻辑循环依赖时,此操作才会失败
大多数循环导入实际上不是逻辑循环导入,而是引发importorror
错误,因为import()
在调用时计算整个文件的顶级语句的方式
如果您确实希望您的导入位于顶部,则几乎可以避免这些导入程序
:
以这种循环输入为例:
应用程序A
应用程序B
来自David Beazley的精彩演讲,1:54:00
,这里有一种在python中处理循环导入的方法:
def dostuff(self):
from foo import bar
...
try:
from images.serializers import SimplifiedImageSerializer
except ImportError:
import sys
SimplifiedImageSerializer = sys.modules[__package__ + '.SimplifiedImageSerializer']
这将尝试导入SimplifiedImageSerializer
,如果由于已导入而引发了ImportError
,它将从importcache中提取它
附言:你必须用大卫·比兹利的声音阅读整篇文章。我完全同意蟒蛇侠的回答。但我偶然发现了一些代码,这些代码在循环导入中存在缺陷,并在尝试添加单元测试时引发了问题。因此,要在不更改任何内容的情况下快速修补,您可以通过执行动态导入来解决问题
# Hack to import something without circular import issue
def load_module(name):
"""Load module using imp.find_module"""
names = name.split(".")
path = None
for name in names:
f, path, info = imp.find_module(name, path)
path = [path]
return imp.load_module(name, f, path[0], info)
constants = load_module("app.constants")
再说一次,这不是一个永久的解决办法,但可能会帮助一些人