Question about circular imports

F

Frank Millman

Hi all

I seem to have a recurring battle with circular imports, and I am trying to
nail it once and for all.

Let me say at the outset that I don't think I can get rid of circular
imports altogether. It is not uncommon for me to find that a method in
Module A needs to access something in Module B, and a method in Module B
needs to access something in Module A. I know that the standard advice is to
reorganise the code to avoid this, and I try to do this where possible, but
for now I would like to address the question of how to handle the situation
if this is otherwise unavoidable.

The problem is clearly explained in the Python Programming FAQ -

"Circular imports are fine where both modules use the "import <module>" form
of import. They fail when the 2nd module wants to grab a name out of the
first ("from module import name") and the import is at the top level. That's
because names in the 1st are not yet available, because the first module is
busy importing the 2nd."

Having recently reorganised my code into packages, I find that the same
problem arises with packages. Assume the following structure, copied from
the Tutorial -

sound/
__init__.py
formats/
__init__.py
wavread.py
wavwrite.py

The following fails -

in wavread.py -
from formats import wavwrite [this works]

in wavwrite.py -
from formats import wavread [this fails with ImportError]

I can think of two solutions - one is cumbersome, the other may not be good
practice.

The first solution is -

in wavread.py -
import formats.wavwrite

in wavwrite.py -
import formats.wavread

I then have to use the full path to reference any attribute inside the
imported module, which I find cumbersome.

The second solution is -

in formats/__init__.py
import sys
sys.path.insert(0, __path__[0])

in wavread.py -
import wavwrite

in wavwrite.py -
import wavread

This works, but I don't know if it is a good idea to add all the sub-package
paths to sys.path. I realise that it is up to me to avoid any name clashes.
Are there any other downsides?

So I guess my question is -

- is there a better solution to my problem?
- if not, is my second solution acceptable?

If not, I seem to be stuck with using full path names to reference any
attributes in imported modules.

I am using Python3 exclusively now, if that makes any difference.

Any advice will be appreciated.

Frank Millman
 
O

OKB (not okblacke)

Frank said:
The first solution is -

in wavread.py -
import formats.wavwrite

in wavwrite.py -
import formats.wavread

I then have to use the full path to reference any attribute inside
the imported module, which I find cumbersome.

This isn't really true. If this is the only thing you're worried
about, you can always do the "manual" version of a "from X import Y":

import formats.wavread
wavread = formats.wavread

wavread.someFunc() # refers to functions in module formats.wavread.

Also, I'm too lazy to check right now, but I wouldn't be suprised
if "mport formats.wavread as wavread" also works even in the circular
case.

--
--OKB (not okblacke)
Brendan Barnwell
"Do not follow where the path may lead. Go, instead, where there is
no path, and leave a trail."
--author unknown
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,049
Latest member
Allen00Reed

Latest Threads

Top