views:

46

answers:

3

This is probably really simple, but I don't understand it. The following works:

foo.py

class Foo:
    pass

bar.py

module = __import__('foo')
foo = module.__dict__['Foo']

Afterwards, foo is the class foo.Foo as expected.


Yet, if I put a.py into a package, it stops working:

qux/__init__.py

(empty file)

qux/foo.py

class Foo:
    pass

bar.py

module = __import__('qux.foo')
foo = module.__dict__['Foo']

Running python bar.py gives me KeyError: 'Foo', but the module import is still successful.

What's going on, and how do I get it to work?

+3  A: 

__import__ applied to nested module names returns the toplevel module/package - which is qux here. All modules are, however, inserted into sys.modules, so you can simply lookup qux.foo in there.

See the PyDoc on __import__() -it's all described there.

Alexander Gessler
Strange inconsistent behaviour, but it works now. Thanks!
Thomas
Note that 'import qux.foo' works analogously -- `qux` ends up in the local namespace, but `foo` is only accessible as an attribute of `qux`.
Walter Mundt
@Walter Mundt: It makes more sense now, thanks.
Thomas
@Alexander Gessler: Indeed, it suddenly and mysteriously appeared in the docs now that I look again: "When the name variable is of the form package.module, normally, the top-level package (the name up till the first dot) is returned, not the module named by name. However, when a non-empty fromlist argument is given, the module named by name is returned."
Thomas
+1  A: 

You need to use the fromlist parameter to reference a submodule:

temp = __import__('qux.foo', globals(), locals(), ['Foo'], -1)
foo = temp.Foo
Bob
+2  A: 

If you want to import a submodule, you can do something like this:

package = __import__('qux', fromlist=['foo'])
module = getattr(package, 'foo')

Note that with a fromlist the __import__ returns the most nested name in the first parameter, so you could substitute baz.bar.qux in the __import__ call to access the baz.bar.qux.foo module.

Walter Mundt