Circular Dependancies

Thomas Wouters thomas at xs4all.net
Mon May 1 02:37:32 EDT 2000


On Mon, May 01, 2000 at 02:00:09AM +0000, Josh Tompkins wrote:

> I've read in a couple of places that circular dependancies are not a good 
> thing to have in a program.  I'm actually kind of curious:  why is this?  
> Is it a style thing, or something that can actually confuse the 
> interpreter/compiler?

Actually, there are two (or more ?) kinds of circular dependancies:
variables containing each other, and modules that include eachother.

An example of the first is:

>>> a = []
>>> b = []
>>> a.append(b)
>>> b.append(a)

If you then do
>>> del a,b
you can never reach a or b again, but they aren't removed from memory
either, because both are still referenced to (by the other.) In other words,
it's a memory leak. This kind of thing is easy to step into if you are
fiddling with traceback()s in try/except clauses -- you quickly end up with
a traceback containing a variable, like a namespace, that contains a
reference to the traceback itself.

The other thing is fortunately more immediately visible, and happens when
you have to modules include eachother, like so:

# file spam.py
import eggs
wants = None
class Ham(eggs.Eggs):
	pass

# file eggs.py
import spam
class Eggs:
	pass
if spam.wants:
	[...]

The Python parser reads each file line by line, and actually executes the
files like that. It starts to load spam.py (provided that's the script you
call, or module you load first,) reaches 'import eggs', starts to read
'eggs', reads 'import spam', notices it's already reading in the file
'spam.py' -- not in its entirity, but there's nothing it can do about that
-- so continues, and at the line 'spam.wants' it tries to retrieve the value
of the 'wants' entry in the spam namespace. But since the 'wants' entry
hasn't been created yet, this fails with an attribute error:

>>> import spam
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "spam.py", line 2, in ?
    import eggs
  File "eggs.py", line 5, in ?
    if spam.wants:
AttributeError: wants

The best solution is 'dont do that then'. Another workable solution is to
put import statements at the last possible moment -- inside functions,
classes, or right after you define all classes and functions but before you
start with actual code that is executed during (the first) import. The
problem with this is that it tends to get hairy over time, when you forget
why that order is so specific. And we thought python was easy to maintain !
:-)

Improve-the-list-quality--quote-the-FAQ-today-ly y'rs, ;-)
-- 
Thomas Wouters <thomas at xs4all.net>

Hi! I'm a .signature virus! copy me into your .signature file to help me spread!




More information about the Python-list mailing list