Reputation: 191
Here's a python module. foo
is in sys.path
.
foo\
__init__.py
bar\
__init__.py
base.py
class Base(object)
derived.py
import foo.bar.base as base
class Derived(base.Base)
I've got nothing fancy going on yet. If I want to instantiate the Derived class from the derived
module, I can do that easily enough:
import foo.bar.derived as derived
print(derived.Derived())
However, I'd like to just import the bar
module and call bar.Derived()
, because I plan to have lots of classes within lots of different modules, and I don't want to deal with all these tentacular import paths. My understanding is that I can simply import Derived into the namespace of the bar
module, by modifying my project like so:
foo\
__init__.py
bar\
__init__.py
from foo.bar.derived import Derived
base.py
class Base(object)
derived.py
import foo.bar.base as base
class Derived(base.Base)
Now I should be able to do the following:
import foo.bar as bar
print(bar.Derived())
But I get an AttributeError complaining that the foo
module has no submodule called bar
:
test.py (1): import foo.bar
foo\bar\__init__.py (1): from foo.bar.derived import Derived
foo\bar\derived.py (1): import foo.bar.base as base
AttributeError: 'module' object has no attribute 'bar'
In fact, my original test code (at top) doesn't work either! As soon as I try to import foo.bar
, I get errors.
What I can gleam from this error is that the import statement in __init__.py
causes derived.py
to be executed before bar
is fully loaded, and therefore it can't import the module (also from bar
) which contains its own base class. I'm coming from the C++ world, where ultra-nested namespaces aren't as integral and a simple forward declaration would negate this problem, but I've been led to believe that what I'm looking for is possible and at least a somewhat acceptably Pythonic solution. What am I doing wrong? What's the correct way to make classes from a submodule available in the parent module's namespace?
Upvotes: 2
Views: 4671
Reputation: 29680
in derived.py, use this:
EDIT: as JAB pointed out, implicit relative imports are deprecated, to the following isn't recommended (although it does work still in Python 2.7 - with no deprecation errors!).
import base # this is all you need - it's in the current directory
Instead, use:
from . import base #
(or)
from foo.bar import base
instead of:
import foo.bar.base as base
This will solve both your errors (since they're from the same issue). Your import doesn't work since there is no base
function or class inside the foo.bar.base module.
Upvotes: 1
Reputation: 21079
If you're working with Python 2.5 or later, try using explicit relative imports (http://www.python.org/dev/peps/pep-0328/#guido-s-decision):
test.py (1): import foo.bar
foo\bar\__init__.py (1): from .derived import Derived
foo\bar\derived.py (1): from . import base
(Note that if you are indeed working with Python 2.5 or 2.6, you'll need to include from __future__ import absolute_import
in your modules.)
Upvotes: 5