NameError in cross imports of modules

Thomas Wouters thomas at xs4all.net
Sat Feb 3 21:31:11 EST 2001


On Sat, Feb 03, 2001 at 09:31:01PM +0200, Pearu Peterson wrote:

> I have two classes defined in separate files and both classes use each
> other:

> File A.py:
>   from B import *
>   class A:
>       def asB(self): return B()

> File B.py:
>   from A import *
>   class B:
>       def asA(self): return A()
> 
> In Python session I get NameError:

> >>> from A import *
> >>> from B import *
> >>> B().asA()
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
>   File "B.py", line 5, in asA
>     return A()
> NameError: global name 'A' is not defined

> but

> >>> A().asB()
> <B.B instance at 0x810ea4c>

> Note: I am not interested in converting the 'from-import' statements to
> 'import' statements, rather I have collected the classes A and B into the
> same file but it's really inconvenient to maintain a large package in one
> file :(

You really should be interested in not using from-import; it solves your
problem. It works like this:

You execute 'from A import *':
  'A' has not been loaded yet; A.py is found and loaded:
  A new module object is created, and stored in sys.modules['A']
  A.py is executed, in the namespace of the newly created module:
    On the first line, the interpreter finds 'from B import *'.
    'B' has not been loaded yet; B.py is found and loaded:
      A new module object is created and stored in sys.modules['B']
      B.py is executed, in the namespace of the newly created module.
      On the first line, the interpreter finds 'From A import *'.
      'A' has already been loaded (it's present in sys.modules)
      'A' is retrieved from sys.modules, and scanned for names: none found
      B executes the rest of the code, defining class B.
    A retrieves module 'B' from sys.modules, and scans it for names: B found
    A executes the rest of the code, defining class A.

(I know from your posting you know at least part of this, but it's also to
educate others who might not :)

By the time 'B' loads 'A' (too early), there is no class 'A' to from-import,
and because you use 'from A import *', it isn't added later. Where we to
'automatically' reload the 'right' module (magically finding out the right
time and module to reload) we could very easily start looping. In fact, this
entire behaviour is intended to avoid looping. 

> >>> reload(sys.modules['B'])  --- is needed in order to fix the
>                            NameError: module B will be imported
>                            "completely".

This is not true, and implies that you didn't really understand what was
happening. 'B' isn't the one incompletely imported, 'A' was! And because you
use 'from-import-*', which makes *copies* of the variables (which are
themselves references) in a module, reloading 'A' won't help, because 'B'
won't see the new variables.

You have two real ways to fix this: don't use 'from-import *'. Honestly, it is
the best solution. 'from-import *' was not intended for this kind of
hackery, and as far as I'm concerned there are only two viable uses: the way
os.py uses it (import any and all symbols from a platform-dependant C
module) and the way Mailman uses it (import all symbols from a template
config file into the user-editable config file, so it only needs to contain
overriding values.) I still owe Fred a "From module import * considered
harmful" tutorial-section ;-P If prefixing all module variables with the
module name is too painful because the module name is too long or unclear,
consider using 'import my_long_module as _a' or some such.

Alternatively, move the 'from-import *' to the bottom of the file, instead
of the top. That way, 'A' will have defined all the variables before it
starts loading B, and B won't have any problem finding them. Definately the
inferior solution, though ;)

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