3

Description

I have a package structure where various modules need to obtain information from different ones and therefore I use relative imports. It happens that those relative imports are nested in some way.
I'll just present you the package structure I have:

.
├── core
│   ├── __init__.py
│   ├── sub1
│   │   ├── __init__.py
│   │   └── mod1.py
│   └── sub2
│       ├── __init__.py
│       ├── mod1.py
│       └── sub1
│           ├── __init__.py
│           └── mod1.py
└── main.py

The files contain the following statements:

main.py:

print __name__
import core.sub2.mod1

core/sub2/mod1.py

print __name__
import sub1.mod1

core/sub2/sub1/mod1.py

print __name__
from ...sub1 import mod1

core/sub1/mod1.py

print __name__
from ..sub2 import mod1

Visualization

A visualization of the imports:

Visualization

Problem

When I run python main.py I get the following error (I substituted the absolute file paths with ./<path-to-file>):

__main__
core.sub2.mod1
core.sub2.sub1.mod1
core.sub1.mod1
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    import core.sub2.mod1
  File "./core/sub2/mod1.py", line 2, in <module>
    import sub1.mod1
  File "./core/sub2/sub1/mod1.py", line 2, in <module>
    from ...sub1 import mod1
  File "./core/sub1/mod1.py", line 2, in <module>
    from ..sub2 import mod1
ImportError: cannot import name mod1

From this question I learned that python uses the __name__ attribute of a module to resolve its location within the package. So I printed all the names of the modules and they seem to be alright! Why do I get this ImportError then? And how can I make all the imports work?

Community
  • 1
  • 1
a_guest
  • 34,165
  • 12
  • 64
  • 118
  • Did you try adding `__init__.py` to your root location? – dmitryro Jul 30 '16 at 12:47
  • This won't help because I'm not issuing any import above `core`'s level. `core` is a package and `main.py` just uses this package. – a_guest Jul 30 '16 at 12:51
  • 1
    You have an import cycle. Circular imports tend to fail when you're using `from module import name` syntax, since the `name` might not be defined yet in `module` if it's not yet fully loaded. Later versions of Python 3 have improved this a little bit, but it's still quite harry. The general recommendation is to avoid circular imports whenever you can, and use plain old absolute imports (`import foo.bar.baz`, no `from`, no `as`) whenever you can't. Some programmers will go further and suggest that circular imports suggest bad module design (that things are too closely coupled across packages). – Blckknght Jul 30 '16 at 13:36
  • @Blckknght Your comment made me think about my package structure and I realized that the structure actually wasn't optimal and so eventually I could remove the import cycle by restructuring it. I guess what you said holds under almost all circumstances, there's always the possibility to structure a package without import cycles (and I feel that this often is a more intuitive approach to it). – a_guest Aug 03 '16 at 09:16

1 Answers1

0

As @Blckknght pointed out, you have an import cycle. you can eliminate this annoying cycle by reorganizing your code.

But if you don't have to invoke core.sub2.mod1 immediately when importing core.sub1.mod1, there is a simple way to fix it.

You can import core.sub2 and invoke core.sub2.mod1 later.

core/sub1/mod1.py

print __name__
from .. import sub2
def foo():
    t = sub2.mod1
gzc
  • 8,180
  • 8
  • 42
  • 62
  • This won't work. How do you access `sub2.mod1`? You have to make it available via `sub2.__init__`: `import mod1`. And the moment you do `from .. import sub2` `sub.__init__` will be evaluated and you'll end up in an import cycle again. – a_guest Aug 03 '16 at 09:10
  • @a_guest You didn't show `sub2/__init__.py` content at first so that I assumed this file is blank. If you remove `import mod1` from `sub2._init__`, this will work. – gzc Aug 03 '16 at 12:21