Recursive import: 'import' vs. 'from ... import ...'

Viewed 5857

I have two files that need to use different functions from each other.

file1.py:

import file2   # from file2 import y2

def x1():
    print "x1"

def x2():
    print "x2"
    file2.y2()

file2.py:

import file1   # from file1 import x1

def y1():
    file1.x1()
    print "y"

def y2():
    print "y2"

if __name__ == "__main__":
    y1()

I would like to know why using import file1 is working, but importing just the specific function from file1 (from file1 import x1) is not?

Traceback (most recent call last):
  File "file2.py", line 1, in <module>
    from file1 import x1
  File "file1.py", line 1, in <module>
    import file2
  File "file2.py", line 1, in <module>
    from file1 import x1
ImportError: cannot import name x1

I've read this about imports:

import X

Imports the module X, and creates a reference to that module in the current namespace. Then you need to define completed module path to access a particular attribute or method from inside the module (e.g.: X.name or X.attribute)

from X import *

Imports the module X, and creates references to all public objects defined by that module in the current namespace (that is, everything that doesn’t have a name starting with _) or whatever name you mentioned.

Or, in other words, after you've run this statement, you can simply use a plain (unqualified) name to refer to things defined in module X. But X itself is not defined, so X.name doesn't work. And if name was already defined, it is replaced by the new version. And if name in X is changed to point to some other object, your module won’t notice.

This makes all names from the module available in the local namespace.

3 Answers

Another solution is to import modules only when you need them. For example, in your case, it could be solved by the below method:

file1.py

# insted of importing file2 here

def x1():
    print "x1"

def x2():
    print "x2"
    import file2    # import here when you need it
    file2.y2()

file2.py

This file content should be the same as mentioned in the question.

Related