Problem with modules refering to each other

Gordon McMillan gmcm at hypernet.com
Sun Aug 8 11:17:10 EDT 1999


Phil Hunt writes:

> I have two python modules, both of which need to refer to classes
> defined in the other one. How do I do this? 
> 
> I am currently putting at the start of each module a line of the
> form:
> 
>    from theOtherModule import *
> 
> However, this is not working. My modules -- greatly simplified --
> look like this:
> 
>    #bak.py
>    from hhh import *
>    ti = AnHhhClass()
>    print ti
> 
> and:
> 
>    #hhh.py
>    from bak import *
>    class AnHhhClass: pass
> 
> When I run ``python bak.py'', I get the error message 
> ``NameError: AnHhhClass''.

Plumbing rule #1: bak.py runs, Python hits the line with the "import" 
statement, moves over to hhh.py. In hhh.py it hits the "import" line. 
To protect itself against infinite recursion, it looks to see if 
bak.py is being imported. In your case it's not, because what you 
think of as "bak" is actually "__main__". So it starts importing bak 
as a module. Hits the import line. Looks up hhh.py. This time it 
detects recursion, so it just goes on, on the theory that whoever is 
importing hhh.py will eventually complete the process. Which is true. 

Plumbing rule #2: from module import ... doesn't do what you want. It 
imports module, but not into your namespace. It takes what it finds 
in the imported namespace and creates vars of the same name in your 
namespace.

So when bak.py is imported, nothing has been bound into it's
namespace from hhh, because hhh's namespace is empty at that point.
Since the following line expects something from hhh to be bound into
bak.py's namespace, it fails.

So how do you fix this? 

First, you never, ever use "from module import ..." unless (1) 
the module has been specifically designed to allow this (see 
what Tkinter or threading does to allow this) and (2) there are no 
recursive imports going on.

Second, if you're doing recursive imports, you don't make any 
references to items in the other module at the top level. They won't 
be resolvable until the top level has been completely scanned.

Third, you remember that the script you run is not imported under 
it's own name. It's in the import list, but as "__main__". Forgetting 
this yields 2 copies of your module, and strange errors where vars 
you set to new values don't change.

So bak.py should say:

import hhh

def doit()
  it = hhh.AnHhhClass()
  print it

And you should run a script that says:

import bak

bak.doit()

- Gordon




More information about the Python-list mailing list