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 <rep...@bugs.python.org> <http://bugs.python.org/issue23203> _______________________________________ _______________________________________________ Python-bugs-list mailing list Unsubscribe: https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com