Rob Watts
Rob Watts

Reputation: 7146

Why does one __import__ statement affect the validity of the next one?

I was looking at some code with two __import__ statements, and the second __import__ statement doesn't work unless the first one has already been run.

The directory structure is like this:

dir1
 |-__init__.py
 |-subdir1
 |  |-__init__.py
 |  |-file1.py
 |  |-file2.py
 |
 |-subdir2
    |-__init__.py
    |-file1.py
    |-file2.py

The code has two __import__ statements:

m = __import__('dir1.'+subdir1, fromlist=[file1])
...
m = __import__(file2, fromlist=[class_inside_file2])

The first one makes sense - it is roughly the equivalent of doing

from dir1.subdir1 import file1

but allows for the subdirectory and file to be provided dynamically. It is the second statement that I don't understand why it works. It looks like it should be the equivalent of

from file2 import class_inside_file2

This shouldn't work as file2.py is in subdir1, but my current working directory is two levels above that. Additionally, all of the __init__.py files are empty.

As you would expect, the second import statement fails with an ImportError if it is run by itself. However, after the first import statement has run the second one works. Why?

Upvotes: 8

Views: 244

Answers (2)

Peter Gibson
Peter Gibson

Reputation: 19554

It is not just the __import__ statements as I can't replicate this behavior.

$ mkdir -p dir1/subdir1 dir1/subdir2
$ touch dir1/__init__.py dir1/subdir1/__init__.py dir1/subdir2/__init__.py
$ echo "print '1.1'" > dir1/subdir1/file1.py
$ echo "print '1.2'" > dir1/subdir1/file2.py
$ echo "print '2.2'" > dir1/subdir2/file2.py
$ echo "print '2.1'" > dir1/subdir2/file1.py

Gives the following structure:

$ find . -name "*.py"
./dir1/__init__.py
./dir1/subdir1/__init__.py
./dir1/subdir1/file1.py
./dir1/subdir1/file2.py
./dir1/subdir2/__init__.py
./dir1/subdir2/file1.py
./dir1/subdir2/file2.py

However the 2nd __import__ command you've posted fails as expected:

$ python
Python 2.7.6 (default, Nov 18 2013, 11:23:24)
[GCC 4.2.1 Compatible Apple LLVM 4.2 (clang-425.0.24)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> subdir1 = 'subdir1'
>>> file1 = 'file1'
>>> m = __import__('dir1.'+subdir1, fromlist=[file1])
1.1
>>> file2 = 'file2'
>>> class_inside_file2 = '*'
>>> m = __import__(file2, fromlist=[class_inside_file2])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: No module named file2

Upvotes: 4

Rob Watts
Rob Watts

Reputation: 7146

It turns out the explanation is rather dumb. file1 modifies sys.path to add subdir1 to the path. With subdir1 on the path, it can obviously find file2 directly without having specify any packages.

Moral of the story - side effects (like things happening when you import a module) are dumb because it can frequently cause issues that seem bizarre and can be hard to diagnose.

Upvotes: 5

Related Questions