3

I have two modules forming a circular import under a package

/test
  __init__.py
  a.py
  b.py

a.py

import test.b
def a():
  print("a")

b.py

import test.a
def b():
  print("b")

But when I do "import test.a" from python interactive interpreter it throws AttributeError: module 'test' has no attribute 'a'

>>> import test.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test/a.py", line 2, in <module>
    import test.b as b
  File "test/b.py", line 1, in <module>
    import test.a as a
AttributeError: module 'test' has no attribute 'a'

But when I change it to from test import a and from test import b, it works fine.

So what is the difference?

I am using python3.5


Edit 1:

As asked by @Davis Herring, python2 behaves differently. when using import test.a as a format there is no error thrown.

Python 2.7.12 (default, Dec  4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import test.a

However, when using from test import a it throws error

Python 2.7.12 (default, Dec  4 2017, 14:50:18)
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import test.a
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "test/a.py", line 2, in <module>
    from test import b
  File "test/b.py", line 1, in <module>
    from test import a
ImportError: cannot import name a
wei
  • 6,629
  • 7
  • 40
  • 52

1 Answers1

1

import does 3 things:

  1. Find and load modules (typically from disk) not already in sys.modules.
  2. After each newly loaded module finishes execution, assign it as an attribute on its containing package (if any).
  3. Assign a variable in the scope of the import to allow access to the nominated module.

There are many tricks:

  1. import a.b assigns a variable a, so that you can write a.b like in the import.
  2. import a.b as c assigns c to be the modulea.b, not a as before.
  3. from a import b can select a module or any other attribute of a.
  4. Step #1 of a circular import “succeeds” immediately because the relevant entries in sys.modules are created when the import begins.

Points #2 and #4 explain the failure with a circular import a.b as b: the circular import goes straight to step #3, but then the import attempts to load the attribute from step #2 of the outer import which has yet to occur.

The from ambiguity used to cause the same trouble, but a special fallback to look in sys.modules was added in 3.5 to support this case. The same approach would probably work for import a.b as b, but that hasn’t happened yet.

Davis Herring
  • 36,443
  • 4
  • 48
  • 76