Namespace confusion

Martin von Loewis loewis at informatik.hu-berlin.de
Fri Sep 14 08:56:47 EDT 2001


Luna Tic <lunatic at beyond.net> writes:

> I get an error message certainly because of the interdependence of
> those two modules, am I right?

Indeed. Your problem slightly varies depending on whether you attempt
to import foo or bar. Suppose your application does "import foo".
Then you get the following sequence of events

1. import foo. an empty foo is added to sys.modules, which gets
   filled as execution of foo progress
2. foo executed import bar. bar is added to sys.modules, and
   execution of bar starts.
3. bar performs import foo, and gets a reference to the module
   whose initialization is in progress.
4. class bacon is defined; initialization of bar completes.
5. initialization of foo resumes, defining class foo
6. i = foo() is executed, but in substeps: first, the right-hand
   side is executed, then the assignment is performed, so:
6a) a foo.foo instance is created
 b) its __init__ is invoked, performing bar.bacon()
 c) a bar.bacon() instance is created
 d) its __init__ is invoked, performing foo.i.list.append
    At this time, neither foo.i is assigned, nor does the object
    that would be assigned have a list attribute yet.

If your application starts with "import bar", it does not get that far:

1. import bar. Add bar to sys.modules.
2. performs import foo. Add foo to sys.modules
3. inside foo: import bar; obtain reference to bar
4. define class foo.foo
5. perform i = foo()
5a) create foo.foo instance
 b) call its __init__, referring to bar.bacon.
    Class bacon has not yet been defined.

If your main program is "python foo.py", you are in more troubles:
foo.py will define the module __main__, not the module foo. So the
import foo will load a second copy of foo. If that is your problem,
you should avoid having global variables in the __main__ module; write
a separate application script instead.

To avoid the problem in the second run, delay imports as much as
possible:


# foo.py
class foo:
    def __init__(self):
        import bar
        self.attr = bar.bacon()
        self.list = []

i = foo()

# bar.py
class bacon:
    def __init__(self):
        import foo
        foo.i.list.append(1)

Now, importing bar will do nothing but create a class bacon; foo will
be imported only when a bacon instance is created. Importing foo will
still run into the problem that i is not assigned. To avoid this, you
have to rearrange the constructors. Here are a couple of options:

A. Delay setting of attr
# foo.py
class foo:
    def __init__(self):
        self.list = []

i = foo()
import bar
self.attr = bar.bacon()

# bar.py
class bacon:
    def __init__(self):
        import foo
        foo.i.list.append(1)

B. Delay appending bacons

# foo.py
class foo:
    def __init__(self):
        import bar
        self.list = []
        self.attr = bar.bacon()

i = foo()
i.attr.register()

# bar.py
class bacon:
    def register(self):
        import foo
        foo.i.list.append(1)

C. register into different variable

# foo.py
class foo:
    def __init__(self):
        import bar
        self.attr = bar.bacon()
        self.list = []

i_list = []
i = foo()
i.list = i_list

# bar.py
class bacon:
    def __init__(self):
        import foo
        foo.i_list.append(1)

I don't know what you problem you are really trying to solve; it seems
you'd be better of with less cyclic structures.

Regards,
Martin



More information about the Python-list mailing list