Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Two Python modules require each other's contents - can that work?

I have a Bottle webserver module with the following line:

from foobar.formtools import auto_process_form_insert 

And the foobar.formtools module contains this line:

from foobar.webserver import redirect, redirect_back 

Of course, both result in the following errors (respectively):

ImportError: cannot import name auto_process_form_insert
ImportError: cannot import name redirect

Is it simply a fact that in Python two modules can't import each other and all module imports must be hierarchical in nature, or am I doing something wrong? Alternatively, is there a workaround short of placing all these nice functions in new modules?

like image 257
Hubro Avatar asked Jul 28 '12 05:07

Hubro


People also ask

Can 2 Python modules import each other?

Modules can import each other cyclically, but there's a catch. In the simple case, it should work by moving the import statements to the bottom of the file or not using the from syntax.

Can modules use other modules?

Modules can import other modules.

Can Python scripts import each other?

As explained in my answer, it is possible for modules to import each other, but if you need to do that, you may want to reconsider your design.

Do Python modules need to be in the same folder?

No, files can be imported from different directories.


2 Answers

Modules can import each other cyclically, but there's a catch. In the simple case, it should work by moving the import statements to the bottom of the file or not using the from syntax.

Here's why that works:

When you import a module, Python first checks sys.modules. If it's in there, it just imports from there. If it's not there, it tries to import it in the normal way; basically, it finds the file and runs the stuff in it.

Running a module populates the module's contents. For example, say we have this module, creatively named example_opener:

import webbrowser  def open_example():     webbrowser.open('http://www.example.com/') 

At the start, the module is empty. Then Python executes:

import webbrowser 

After that, the module only contains webbrowser. Then Python executes this:

def open_example():     webbrowser.open('http://www.example.com/') 

Python creates open_example. Now the module contains webbrowser and open_example.

Say webbrowser contained this code:

from example_opener import open_example  def open(url):     print url 

Say example_opener is imported first. This code is executed:

import webbrowser 

webbrowser has not yet been imported, so Python executes the contents of webbrowser:

from example_opener import open_example 

example_opener has been imported, but not yet fully executed. Python doesn't care. Python pulls the module out of sys.modules. At this point, example_opener is still empty. It hasn't defined open_example yet, nor even completed importing webbrowser. Python can't find open_example in example_opener, so it fails.

What if we imported open_example from the end of webbrowser and webbrowser from the end of example_opener? Python would start by executing this code:

def open_example():     webbrowser.open('http://www.example.com/') 

webbrowser does not exist yet, but it doesn't matter until open_example is called. Now example_opener contains only open_example. It then executes:

import webbrowser 

It has not been imported yet, so Python executes webbrowser. It starts:

def open(url):     print url 

It defines open. Then it executes:

from example_opener import open_example 

example_opener is in sys.modules, so it uses that. example_opener contains open_example, so it succeeds. Python finishes importing webbrowser. That concludes importing webbrowser from example_opener. That's the last thing in example_opener, so the import of example_opener finishes, successful, as well.

like image 129
icktoofay Avatar answered Oct 11 '22 22:10

icktoofay


Don't do from ... import .... Just do import ... and reference its objects using the module name.

like image 42
pyrospade Avatar answered Oct 11 '22 23:10

pyrospade