Reputation: 453
Sorry for the confusing title, I tried to fit as much of the problem in the title.
I have a module(say ModuleA
) which contains class definitions of some Tkinter GUI elements.
These elements also have certain events/functions bound/binded with them(such as '<Button-1>','<Button-2>'...
.
Now there's another module(say ModuleB
). This is the main(core of the) program. In this module I import ModuleA
to use its objects. The objects of ModuleA
have a place in an array(say Array1
); and also there is another array(say Array2
) which stores the value of just one of the data-member of each of the objects of Array1
, and these are the data-members which are manipulated by the Event Bindings
.
So the problem is that when an Event
occurs, the objects(stored in Array1
) of ModuleA
respond visually as needed, but in the backend their corresponding data-member values must also be updated in Array2
accordingly.
#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
In the Event Bindings
of the objects of ModuleA
I added the required function(say foo
) which will handle the required array manipulations and is defined in ModuleB
as it has to handle the Array2
of ModuleB
.
But this gave me an error global name 'foo' is not defined
So in the class-definition of ModuleA
I added global foo
, which too didn't solve it.
Finally I tried inserting in ModuleA
from ModuleB import foo
Which raised an ImportError
saying it cannot import foo(which I guess is because ModuleB
itself is importing ModuleA
hence circular reference)
One solution clearly visible is to copy entire ModuleA
(containing class definitions) to ModuleB
.
But this is not always practical and not too pythonic either.
Please help.
Upvotes: 0
Views: 180
Reputation: 3857
You should check this link out : http://effbot.org/zone/import-confusion.htm There is an interesting paragraph about how to handle circular reference by moving the import statement at the end of the module. But IMHO don't try to handle that thing, just refactor your code ;)
Upvotes: 0
Reputation: 104712
Circular imports in Python can be confusing. It's easy to get it wrong, and so it's usually best to avoid them, if possible. However, they are not illegal, and if you're careful they can work just fine.
The import process works like this, when you type import foo
:
sys.modules
dictionary to see if the module foo
has been loaded already. If so, the pre-existing module is simply placed into your current module's namespace (and the process stops there).foo.py
file can be found to load. If none exists, an ImportError
is raised and the process stops.sys.modules
under the name foo
.Now, if the foo
module described above has it's own import
statements, the import process can recurse, loading up the other module before continuing on with the execution of the foo
module's code. But, since the empty module object get added to the sys.modules
dictionary before any more imports are processed, it will never loop all the way around and try to load the same file more than once (in most cases).
There are a few things that can go wrong.
If foo
is being executed as a script (rather than being imported by some other module), it's initial entry in sys.modules
will be under the name __main__
rather than foo
. This means that if foo
gets imported from somewhere else, you'll end up with two copies of the same code. This is an exception to the general rule that a module doesn't get loaded twice, and it can catch you off guard in some cases.
Also, if your circularly imported modules are making top-level accesses to each other, you'll run into trouble if they're imported in the wrong order (or any order, if they both reference each others contents in the wrong way from the top level). You can avoid most problems by ensuring that as little code runs at module load time as possible (put it into functions instead!). Then call the functions from a well defined entry point, after everything has been loaded.
So, in your situation, here are things I'd examine:
from moduleB import foo
? Can you instead doimport moduleB
and access moduleB.foo
later on? This would be the easiest fix that could work (though it will not fix all possible problems).ModuleA
or ModuleB
into a third module, which doesn't need to import either of them, and so eliminate the need for the circular import? This is often a good idea, as it lets you sidestep the whole issue of what gets loaded when.Edit: here's what a fixed version of your modules might look like:
ModuleA.py:
import ModuleB
class bar():
def __init__(self, data):
self.data = data
# do something here that accesses ModuleB.foo
ModuleB.py:
import ModuleA
def foo():
# do whatever
Array1 = [ModuleA.bar(i) for i in range(10)]
Array2 = [whatever]
main.py:
import ModuleB # import order is important here!
import ModuleA
if __name__ == "__main__":
# do stuff
This should be the minimal fix. ModuleA only accesses ModuleB.foo
from within the bar
class's __init__
method, so the circular imports will work OK as long as ModuleB.foo
is defined before any bar
instances are created.
If you want the imports to work in any order, it's a bit trickier. You don't want any work being done at the top-level of the modules:
ModuleA.py is as above.
ModuleB.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]
main.py:
import ModuleA, ModuleB # import order doesn't matter
if __name__ == "__main__":
ModuleB.setupArrays()
# do stuff
This is still a bit of a kludge. If you can break the circular import completely, perhaps the code can be simplified in a more obvious way. For instance, we could pass the callback function as a parameter to the bar
class's constructor:
ModuleA.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
ModuleB:
import ModuleA
def foo():
# do whatever
Array1 = [ModuleA.bar(i, foo) for i in range(10)]
Array2 = [whatever]
Upvotes: 1
Reputation: 2731
Actually you are doing wrong , for suppose take two modules moduleA and moduleB. If you import moduleA into the moduleB then you can't import the moduleB into moduleA if you are trying to do that thing you should get Import error.
let see The wrong way that you are doing
The below one is moduleA.py
import moduleB
print " I am moduleA"
class foo():
pass
here is the moduleB.py
from moduleA import foo
print "I am moduleB"
now execute moduleB.py
python moduleB.py
you will get the ImportError , but it would not happened if you do
python moduleA.py
The above process is quit wrong, python will not allow this type of importing simply here we are creating loop of imports because on each first import the top level code of whole module will be executed of course python will not allow this .
To solve your problem just change the module hierarchy .
Here is the simple solution : If you want the content of both modules (moduleA and moduleB) just create one more module moduleC and import both modules(moduleA and moduleB) there in moduleC and do your necessary stuff.
Please refer the edited stuff , you are doing same thing
Upvotes: 1