Experiment trying to avoid Python circular dependencies -


i have testing environment try understand how python circular dependencies can avoided importing modules import x statement, instead of using from x import y:

test/     __init__.py         testing.py     a/         __init__.py         m_a.py     b/         __init__.py         m_b.py 

the files have following content:

testing.py:

from a.m_a import 

m_a.py:

import b.m_b print b.m_b class a:     pass 

m_b.py:

import a.m_a print a.m_a class b:     pass 

there situation can't understand:

if remove print statements modules m_a.py , m_b.py or m_b.py works ok, if print present @ m_b.py, following error thrown:

file "testing.py", line 1, in <module>   a.m_a import file "/home/enric/test/a/m_a.py", line 1, in <module>   import b.m_b file "/home/enric/test/b/m_b.py", line 3, in <module>   print a.m_a attributeerror: 'module' object has no attribute 'm_a' 

do have ideas?

it "works" print statements removed because you're not doing depends on imports. it's still broken circular import.

either run in debugger, or add print statement after each line, , you'll see happens:

  • testing.py: from a.m_a import a
  • a.m_a: import b.m_b
  • b.m_b: import a.m_a
  • b.m_b: print a.m_a

it's trying access a.m_a before module finished importing. (in fact, can see rest of a.m_a on stack in backtrace.)

if dump out sys.modules @ point, you'll find 2 partial modules named a , a.m_a, if dir(a), there's no m_a there yet.

as far can tell, fact m_a doesn't added a until m_a.py finishes evaluating not documented anywhere in python 2.7 documentation. (3.x has more complete specification of import process—but it's different import process.) so, can't rely on either failing or succeeding; either 1 legal implementation. (but happens fail in @ least cpython , pypy…)


more generally, using import foo instead of from foo import bar doesn't magically solve circular-import problems. solves 1 particular class of circular-import problems (or, rather, makes class moot). (i realize there misleading text in the faq this.)


there various tricks work around circular imports while still letting have circular top-level dependencies. really, it's simpler rid of circular top-level dependencies.

in toy case, there's no reason a.m_a depend on b.m_b @ all. if need prints out a.m_a, there better ways independent package!

in real-life code, there stuff in m_a m_b needs , vice-versa. usually, can separate out 2 levels: stuff in m_a needs m_b, , stuff in m_a that's needed m_b. so, split 2 modules. it's same thing common fix bunch of modules try reach , import main: split utils off main.

what if there m_b needs m_a, needs m_b? well, in case, may have insert level of indirection. example, maybe can pass thing-from-m_b function/constructor/whatever m_a, can access local parameter value instead of global. (it's hard more specific without more specific problem.)

if worst comes worst, , can't remove import via indirection, have move import out of way. may again mean doing import inside function call, etc. (as explained in faq after paragraph set off), or moving code above import, or kinds of other possibilities. consider these last-ditch solutions can't designed cleanly, not roadmap follow designs.


Comments

Popular posts from this blog

css - Which browser returns the correct result for getBoundingClientRect of an SVG element? -

gcc - Calling fftR4() in c from assembly -

Function that returns a formatted array in VBA -