Question about circular imports

Peter Otten __peter__ at web.de
Sun Feb 26 12:12:55 CET 2012


Frank Millman wrote:

> 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.

To cut a long story short, why should circular imports be 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

This should be

import sound.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?

Paths into packages are recipe for desaster. You may end up with multiple 
instances of the same module and your programs will break in "interesting" 
(hard to debug) ways.
 
> 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





More information about the Python-list mailing list