0

抱歉标题令人困惑,我试图在标题中尽可能多地解决问题。


场景:

我有一个模块(比如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 Bindingsof 的对象中,ModuleA我添加了所需的函数(比如foo),它将处理所需的数组操作,并定义ModuleB为它必须处理Array2of ModuleB。但这给了我一个错误global name 'foo' is not defined

ModuleA所以在我添加的类定义中global foo,这也没有解决它。

最后我尝试插入ModuleA

from ModuleB import foo

这提出了一个ImportError说法,它不能导入 foo(我猜这是因为ModuleB它本身正在导入ModuleA因此循环引用)


一个解法

一种清晰可见的解决方案是将整个ModuleA(包含类定义)复制到ModuleB. 但这并不总是实用的,也不是太 Pythonic。

请帮忙。

4

3 回答 3

1

实际上你做错了,因为假设有两个模块 moduleA 和 moduleB。如果您将 moduleA 导入到 moduleB 中,那么如果您尝试执行此操作,则无法将 moduleB 导入到 moduleA 中,您应该会收到 Import 错误。

让我们看看你正在做的错误方式

下面是moduleA.py

import moduleB
print " I am moduleA"
class foo():
     pass

这是模块B.py

from  moduleA import foo
print "I am moduleB"

现在执行 moduleB.py

python moduleB.py

你会得到 ImportError ,但如果你这样做就不会发生

python moduleA.py 

上面的过程是错误的,python 不允许这种类型的导入,这里我们正在创建导入循环,因为在每次第一次导入时,都会执行整个模块的顶级代码,当然 python 不会允许这样做。

要解决您的问题,只需更改模块层次结构。

这是简单的解决方案:如果您想要两个模块(模块A和模块B)的内容,只需再创建一个模块模块C并在模块C中导入两个模块(模块A和模块B)并做您必要的事情。

请参考编辑过的东西,你在做同样的事情

于 2013-01-15T09:04:30.030 回答
1

Python 中的循环导入可能会令人困惑。很容易出错,因此如果可能的话,通常最好避免它们。但是,它们并不违法,如果您小心,它们可以正常工作。

当您键入以下内容时,导入过程的工作方式如下import foo

  1. 首先,Python 检查sys.modules字典以查看模块foo是否已经加载。如果是这样,则预先存在的模块只需放入当前模块的名称空间中(并且该过程会停在那里)。
  2. 如果没有,它会检查是否foo.py可以找到要加载的文件。如果不存在,ImportError则引发 an 并停止该过程。
  3. 如果找到文件,则会创建一个新的空模块对象并将其放入sys.modulesname 下foo
  4. 然后,Python 打开文件并开始执行它,使用在步骤 3 中创建的模块对象作为本地命名空间。

现在,如果foo上面描述的模块有它自己的import语句,导入过程可以递归,在继续执行foo模块代码之前加载另一个模块。但是,由于在处理任何更多导入之前将空模块对象添加到sys.modules字典中,因此它永远不会一直循环并尝试多次加载同一个文件(在大多数情况下)。

有几件事可能会出错。

如果foo作为脚本执行(而不是由其他模块导入),它的初始条目sys.modules将在名称下__main__而不是foo. 这意味着如果foo从其他地方导入,您最终会得到相同代码的两个副本。这是一个模块不会被加载两次的一般规则的一个例外,在某些情况下它会让你措手不及。

此外,如果您的循环导入的模块正在相互进行顶级访问,那么如果它们以错误的顺序(或任何顺序,如果它们都以错误的方式从顶层)。您可以通过确保在模块加载时运行尽可能少的代码来避免大多数问题(改为将其放入函数中!)。然后在加载完所有内容后,从定义明确的入口点调用函数。

因此,在您的情况下,我将检查以下内容:

  1. 你需要做什么from moduleB import foo?您可以改为稍后import moduleB访问吗?moduleB.foo这将是最简单的解决方法(尽管它不会解决所有可能的问题)。
  2. 您是否需要在模块的顶层工作?通常,您可以将对象创建放入工厂函数中,而不是在顶层(这使得解决方案 #1 更频繁地工作)。无论如何,这可能是一个很好的设计理念,因为如果您希望能够更改(或自定义)它们在运行时创建对象的方式(您只需编写第二个工作方式不同的函数,或者添加工厂的论据)。
  3. 您能否将部分代码从不需要导入其中任何一个的第三个模块中移出ModuleA或移入,从而消除循环导入的需要?ModuleB这通常是一个好主意,因为它可以让您回避何时加载的整个问题。

编辑:这是您的模块的固定版本可能的样子:

模块A.py:

import ModuleB

class bar():
    def __init__(self, data):
        self.data = data
        # do something here that accesses ModuleB.foo

模块B.py:

import ModuleA

def foo():
    # do whatever

Array1 = [ModuleA.bar(i) for i in range(10)]
Array2 = [whatever]

主要.py:

import ModuleB # import order is important here!
import ModuleA

if __name__ == "__main__":
    # do stuff

这应该是最小的修复。ModuleA 只能ModuleB.foobar类的__init__方法内访问,因此只要在创建任何实例ModuleB.foo之前定义,循环导入就可以正常工作。bar

如果您希望导入以任何顺序工作,那就有点棘手了。您不希望在模块的顶层完成任何工作:

ModuleA.py 如上。

模块B.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]

主要.py:

import ModuleA, ModuleB  # import order doesn't matter

if __name__ == "__main__":
    ModuleB.setupArrays()
    # do stuff

这仍然是一个小问题。如果你能完全打破循环导入,也许代码可以以更明显的方式简化。例如,我们可以将回调函数作为参数传递给bar类的构造函数:

模块A.py:

# 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

模块B:

import ModuleA

def foo():
    # do whatever

Array1 = [ModuleA.bar(i, foo) for i in range(10)]
Array2 = [whatever]
于 2013-01-15T10:01:58.547 回答
0

你应该检查这个链接:http ://effbot.org/zone/import-confusion.htm 有一段有趣的段落是关于如何通过移动模块末尾的 import 语句来处理循环引用。但是恕我直言,不要尝试处理那件事,只需重构您的代码;)

于 2013-01-17T14:47:05.837 回答