Simple cross import in python

Question:

I want to separate code in different class and put them to different files. However those class are dependent on each other.

main.py:

from lib import A, B

def main():
    a = A()
    b = B()
    a.hello()
    b.hello()

if __name__ == '__main__':
    main()

lib/_init_.py:

from a import A
from b import B

lib/a.py:

import lib.B

class A():
    def __init__(self):
        print "A"

    def hello(self):
        print "hello A"
        b = B()

lib/b.py:

import lib.A

class B():
    def __init__(self):
        print "B"

    def hello(self):
        print "hello B"
        a = A()

Is it possible to do that in Python?

EDIT:

I get this error message:

pydev debugger: starting
Traceback (most recent call last):
  File "eclipse-python/plugins/org.python.pydev_2.7.1.2012100913/pysrc/pydevd.py", line 1397, in <module>
    debugger.run(setup['file'], None, None)
  File "eclipse-python/plugins/org.python.pydev_2.7.1.2012100913/pysrc/pydevd.py", line 1090, in run
    pydev_imports.execfile(file, globals, locals) #execute the script
  File "main.py", line 2, in <module>
    from lib import A, B
  File "lib/__init__.py", line 1, in <module>
    from a import A
  File "lib/a.py", line 1, in <module>
    import lib.B
ImportError: No module named B
Asked By: ts_pati

||

Answers:

Instead of importing the modules on top, you could import the other module within the hello function.

class B():
    def __init__(self):
        print "B"

    def hello(self):
        from lib import A
        print "hello B"
        a = A()
Answered By: Michael_Scharf

If you want to import it only once you can import it in the constructor of the class and make the variable global:

class B():
    def __init__(self):
        global A
        from lib import A
        print "B"

    def hello(self):
        print "hello B"
        a = A()

This would import A into a global variable and make it accessible form within the module.

Answered By: Michael_Scharf

When you have two classes depending on each other usually means that either they really belong to the same module or that you have a too tight coupling that should be resolved using dependency injection.

Now there are indeed a couple corner cases where importing from within the function is the “least worst” solution but that’s still something you should avoid as much as possible.

Answered By: bruno desthuilliers

Your main problem is that you’re trying to import a class, but using syntax that only works to import a module. Specifically, import lib.A is never going to work if A is a class defined in module lib.a (and imported into the top-level namespace of lib).

What I suggest is that you avoid using the from _ import _ syntax unless you really need it. That makes the dependencies much easier to resolve:

lib/a.py:

import lib.b # note, we're not importing the class B, just the module b!

class A():
    def foo(self):
        return lib.b.B() # use the class later, with a qualified name

lib/b.py:

import lib.a # again, just import the module, not the class

class B():
    def foo(self):
        return lib.a.A() # use another qualified name reference

lib/__init__.py:

from a import A # these imports are fine, since the sub-modules don't rely on them
from b import B # they can be the public API for the A and B classes

You could also use relative module imports if you don’t want a and b to be dependent on the name of their package lib.

This is sure to work because neither class A or B actually requires the other to exist yet in order to be defined. It’s only after they’re imported that instances of A need to know about the class B (and vise versa).

If one of the classes inherited from the other, or otherwise used an instance of the other at top level, you’d need to be more careful about which module was loaded up first, or it might still break.

Answered By: Blckknght
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.