Nick Coghlan added the comment:
You can see the difference between the two cases in the bytecode:
>>> dis.dis("import x.y.z")
1 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 (None)
6 IMPORT_NAME 0 (x.y.z)
9 STORE_NAME 1 (x)
12 LOAD_CONST 1 (None)
15 RETURN_VALUE
>>> dis.dis("import x.y.z as bar")
1 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 (None)
6 IMPORT_NAME 0 (x.y.z)
9 LOAD_ATTR 1 (y)
12 LOAD_ATTR 2 (z)
15 STORE_NAME 3 (bar)
18 LOAD_CONST 1 (None)
21 RETURN_VALUE
The aliased version needs to bind the innermost object immediately, so it
fails, since "foo.bar" doesn't get set until *after* the import is finished.
The version without the alias succeeeds, as it doesn't attempt to eagerly
access the attribute before it gets set by the interpreter.
To better handle a similar situation with eager attribute lookups during
import, issue 17636 changed IMPORT_FROM to fall back to looking at sys.modules
when a module attribute it is looking for is missing.
Brett, Eric, perhaps it would be worth changing the bytecode emitted in the
"import x.y.z as name" case to match that for "from x.y import x as name"?
>>> dis.dis("from x.y import z as bar")
1 0 LOAD_CONST 0 (0)
3 LOAD_CONST 1 (('z',))
6 IMPORT_NAME 0 (x.y)
9 IMPORT_FROM 1 (z)
12 STORE_NAME 2 (bar)
15 POP_TOP
16 LOAD_CONST 2 (None)
19 RETURN_VALUE
----------
_______________________________________
Python tracker <[email protected]>
<http://bugs.python.org/issue23203>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe:
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com