很抱歉这个令人困惑的标题,我试图在标题中解决这个问题。
我有一个模块(比如ModuleA
),它包含一些Tkinter GUI元素的类定义。
这些元素还具有与它们绑定/绑定的某些事件/函数(例如'<Button-1>','<Button-2>'...
。
现在还有另一个模块(比如ModuleB
)。这是该计划的主要(核心)。在此模块中,我导入ModuleA
以使用其对象。 ModuleA
的对象在数组中有一个位置(比如Array1
);还有另一个数组(比如Array2
),它存储Array1
每个对象的一个数据成员的值,这些是由数据成员操作的数据成员。 Event Bindings
。
所以问题是当Event
发生时,Array1
的对象(存储在ModuleA
中)会根据需要进行视觉响应,但在后端,它们对应的数据成员值必须也会相应地更新Array2
。
#ModuleA.py
from ModuleB import foo
class bar
data = 1
# some tkinter code
# bind mouse click to function foo of ModuleB
-------------------------------------------------------
#ModuleB.py
from ModuleA import bar
Array1 = [objects of class bar]
Array2 = [value of data of objects in Array1]
def foo(#obj of class bar)
# find index of bar object which called this function in Array1
# accordingly change Array2
在Event Bindings
对象的ModuleA
中,我添加了所需的函数(比如foo
),它将处理所需的数组操作,并在ModuleB
中定义,因为它必须处理Array2
的{{1}}。
但这给了我一个错误ModuleB
因此,在global name 'foo' is not defined
的类定义中,我添加了ModuleA
,这也没有解决它。
最后我尝试插入global foo
ModuleA
提出from ModuleB import foo
说它无法导入foo(我猜是因为ImportError
本身正在导入ModuleB
因此循环引用)
一个清晰可见的解决方案是将整个ModuleA
(包含类定义)复制到ModuleA
。
但这并不总是实用的,也不是太过pythonic。
请帮忙。
答案 0 :(得分:1)
实际上你做错了,因为假设有两个模块 moduleA和moduleB。如果将moduleA导入moduleB,则无法导入 moduleB进入moduleA,如果你想做那件事你应该得到导入错误。
让我们看看你正在做的错误方式
以下是moduleA.py
import moduleB
print " I am moduleA"
class foo():
pass
这是moduleB.py
from moduleA import foo
print "I am moduleB"
现在执行moduleB.py
python moduleB.py
您将获得ImportError,但如果您执行
则不会发生python moduleA.py
上面的过程是退出错误的,python不允许这种类型的导入 简单地说,我们正在创建导入循环,因为在每次首次导入时,整个模块的顶级代码将被执行,当然python将不允许这样做。
要解决您的问题,只需更改模块层次结构。
这是一个简单的解决方案: 如果您想要两个模块(moduleA和moduleB)的内容,只需创建一个模块 moduleC并在moduleC中导入两个模块(moduleA和moduleB)并执行必要的操作。
请参考编辑后的内容,你正在做同样的事情
答案 1 :(得分:1)
Python中的循环导入可能令人困惑。这很容易弄错,所以如果可能的话,通常最好避免它们。但是,它们并非违法,如果你小心,它们可以正常工作。
当您输入import foo
:
sys.modules
字典以查看模块foo
是否已经加载。如果是这样,那么预先存在的模块就会被放置到当前模块的命名空间中(并且进程就会停止)。foo.py
文件。如果不存在,则引发ImportError
并且该过程停止。sys.modules
的名称放入foo
。现在,如果上面描述的foo
模块有自己的import
语句,导入过程可以递归,加载另一个模块,然后继续执行foo
模块码。但是,由于在处理任何更多导入之前,空模块对象被添加到sys.modules
字典中,因此它将永远不会循环并尝试多次加载同一文件(在大多数情况下)。
有些事情可能会出错。
如果foo
作为脚本执行(而不是由其他模块导入),sys.modules
中的初始条目将以__main__
而不是{{1 }}。这意味着如果从其他地方导入foo
,您最终将获得相同代码的两个副本。这是模块不会被加载两次的一般规则的例外,在某些情况下它会让你措手不及。
此外,如果您的循环导入的模块正在相互进行顶级访问,如果它们以错误的顺序导入(或任何顺序,如果它们都引用了错误的相互内容,则会遇到麻烦)从顶层的方式)。您可以通过确保尽可能少的代码在模块加载时运行来避免大多数问题(将其放入函数中!)。然后在加载完所有内容后,从一个定义良好的入口点调用函数。
所以,在你的情况下,这是我要检查的事情:
foo
吗?您可以改为from moduleB import foo
并稍后访问import moduleB
吗?这将是最容易解决的问题(尽管它不会解决所有可能出现的问题)。moduleB.foo
或ModuleA
移动到第三个模块中,而不需要导入其中任何一个模块,从而无需进行循环导入?这通常是一个好主意,因为它可以让你回避在什么时候加载的内容的整个问题。编辑:这是模块的固定版本:
ModuleA.py:
ModuleB
ModuleB.py:
import ModuleB
class bar():
def __init__(self, data):
self.data = data
# do something here that accesses ModuleB.foo
main.py:
import ModuleA
def foo():
# do whatever
Array1 = [ModuleA.bar(i) for i in range(10)]
Array2 = [whatever]
这应该是最小的修复。 ModuleA仅从import ModuleB # import order is important here!
import ModuleA
if __name__ == "__main__":
# do stuff
类的ModuleB.foo
方法中访问bar
,因此只要在任何__init__
实例之前定义ModuleB.foo
,循环导入就会正常工作创建
如果您希望导入按任何顺序工作,那就有点棘手了。您不希望在模块的顶层完成任何工作:
ModuleA.py如上所述。
ModuleB.py:
bar
main.py:
import ModuleA
def foo():
#do stuff
def setupArrays():
global Array1, Array2 # lets us create these global variables
Array1 = [ModuleA.bar(i) for i in range(10)]
Array2 = [whatever]
这仍然是一个问题。如果你可以完全打破循环导入,可能会以更明显的方式简化代码。例如,我们可以将回调函数作为参数传递给import ModuleA, ModuleB # import order doesn't matter
if __name__ == "__main__":
ModuleB.setupArrays()
# do stuff
类的构造函数:
ModuleA.py:
bar
ModuleB:
# No import statement here! Circular imports avoided!
class bar():
def __init__(self, data, callback):
self.data = data
# bind stuff to call the callback function provided
答案 2 :(得分:0)
您应该检查此链接:http://effbot.org/zone/import-confusion.htm 有一个有趣的段落关于如何通过移动模块末尾的import语句来处理循环引用。但恕我直言不会试图处理那件事,只是重构你的代码;)