Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why do these two Python imports work differently?

Assume the following code structure:

#### 1/hhh/__init__.py: empty

#### 1/hhh/foo/__init__.py:
from hhh.foo.baz import *

#### 1/hhh/foo/bar.py:
xyzzy = 4

#### 1/hhh/foo/baz.py:
import hhh.foo.bar as bar
qux = bar.xyzzy + 10

I run python inside 1/ and do import hhh.foo.baz. It fails:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "hhh/foo/__init__.py", line 1, in <module>
    from hhh.foo.baz import *
  File "hhh/foo/baz.py", line 1, in <module>
    import hhh.foo.bar as bar
AttributeError: 'module' object has no attribute 'foo'

Now I replace baz.py with:

# 1/hhh/foo/baz.py:
from hhh.foo.bar import xyzzy
qux = xyzzy + 10

and again do import hhh.foo.baz. Now it works, although I’m loading the same module, only binding a different name.

Does this mean that the distinction between import module and from module import name goes beyond just identifiers? What exactly is going on here?

(I know I can use relative imports to work around all this, but still I’d like to understand the mechanics. Plus I don’t like relative imports, and neither does PEP 8.)

like image 420
Vasiliy Faronov Avatar asked Jul 18 '11 09:07

Vasiliy Faronov


1 Answers

When you write from hhh.foo.bar import xyzzy Python interpreter will try to load xyzzy from module hhh.foo.bar. But if you write import hhh.foo.bar as bar it will try first to find bar in hhh.foo module. So it evaluates hhh.foo, doing from hhh.foo.baz import * . hhh.foo.baz tries to evaluate hhh.foo, hhh.footries to evaluate hhh.foo.baz, cyclic imports, exception.

like image 152
DrTyrsa Avatar answered Nov 05 '22 11:11

DrTyrsa