Import Problems

Robert Kern robert.kern at gmail.com
Fri Apr 27 16:09:29 EDT 2007


Bill Jackson wrote:
> Once again, I am having issues with imports...
> 
> Until now, I thought the general guidelines were to rarely use 'from x 
> import y' syntax, except when you really want to copy names over. 

No, the guideline is to not use "from x import *" except at the interactive
prompt and occasionally in __init__.py's to "copy names over" as you put it.

> However, I have run into issues by following this guideline.  So...
> 
> 1) What is going wrong in the example below?
> 2) What is a good way to handle imports for packages w/subdirectories?
> 
> Here is a sample directory structure:
> 
> importtest/
>    __init__.py
>    test2/
>      __init__.py
>      someclass.py
>      mytest.py
> 
> 
> Here are the definitions of the files:
> 
> # importtest/__init__.py
> from test2 import *
> 
> # importtest/test2/__init__.py
> from someclass import *
> from test2 import *
> 
> # importtest/test2/someclass.py
> class SomeClass:
>     pass
> 
> # importtest/test2/mytest.py
> import importtest
> print importtest.SomeClass
> 
> 
> On import I get the following:
> 
>  >>> import importtest
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
>   File "/home/user/lib/python/importtest/__init__.py", line 1, in ?
>     from test2 import *
>   File "/home/user/lib/python/importtest/test2/__init__.py", line 2, in ?
>     from mytest import *
>   File "/home/user/lib/python/importtest/test2/mytest.py", line 3, in ?
>     print importtest.SomeClass
> AttributeError: 'module' object has no attribute 'SomeClass'
>  >>>
> 
> 
> The problem seems to be an 'order' issue.  importtest/test2/__init__.py 
> has loaded someclass.py, but it doesn't seem to have copied its contents 
> into importtest/__init__.py....perhaps it is because it hasn't finished 
> all of its imports.  Is this correct?

You are right that it is an order issue. The line "from test2 import *" hasn't
finished executing by the time "print importtest.SomeClass" is executed because
the former is trying to execute the latter.

> So what is a good way to deal with this?  In files which contain 
> implementations, I thought it was best not to use 'from x import y', but 
> this seems to be the only way to get this to work:

My recommendation is that inside packages, be as specific as is feasible with
your imports, even if you expose the symbols at a higher level for external
callers. If you have a module whose contents are being exposed in your
__init__.py, never rely on the contents of that __init__.py in that code.
Instead, go straight to the real modules that implement the symbols that you
need. So mytest.py should read:

  from importtest.test2.someclass import SomeClass
  print SomeClass

or

  from importtest.test2 import someclass
  print someclass.SomeClass

-- 
Robert Kern

"I have come to believe that the whole world is an enigma, a harmless enigma
 that is made terrible by our own mad attempt to interpret it as though it had
 an underlying truth."
  -- Umberto Eco




More information about the Python-list mailing list