On Mon, Mar 30, 2009 at 6:17 PM, Guido van Rossum <gu...@python.org> wrote: > [Adding python-dev. I'm quoting the entire original message.] > >> On Thu, Mar 19, 2009 at 6:40 PM, Fredrik Lundh <fredriklu...@google.com> >> wrote: >>> PS. Is it just me, or is import broken in 3.0? Consider this: >>> >>> $ more package\a.py >>> print("in a") >>> >>> import b >>> >>> def a(): >>> print("here") >>> >>> def main(): >>> b.b() >>> >>> $ more package\b.py >>> print("in b") >>> >>> import a >>> >>> def b(): >>> a.a() >>> >>> Under 2.X, this prints "in a" "in b" and "here", as expected. Under >>> 3.0, using the "from . import" form for relative imports, it bombs out >>> with a: >>> >>> in a >>> in b >>> Traceback (most recent call last): >>> File "main.py", line 1, in <module> >>> from package import a >>> File "package/a.py", line 3, in <module> >>> from . import b >>> File "package\b.py", line 3, in <module> >>> from . import a >>> ImportError: cannot import name a >>> >>> Sure, it's a recursive import, but there's no recursive dependency >>> here - nobody will access the module contents until the main program >>> calls the library. What am I missing? > > On Mon, Mar 30, 2009 at 5:44 PM, Guido van Rossum <gu...@python.org> wrote: >> I reproduced this, but it seems to have more to do with "from . import >> ..." than with the Python version. If I add the "from ." before each >> of the imports, "python -c 'import p.a' " fails with roughly the above >> traceback for any version of Python that supports this syntax, while >> without that it passes for any 2.x. >> >> If I use the "from ." syntax in a.py but not in b.py, "import p.a" >> passes but "import p.b" fails. >> >> I'll see if anyone present at the sprints has a clue. > > Made some progress. Anything using "from <whatever> import b" (where > <whatever> is either '.' or 'p') will fail when b's import is not > completed. OTOH using "import p.b" works. I reduced it to: > > p/a.py == "from p import b" > p/b.py == "import a" > python -c "import p.b" > > The reason seems to be that until the outermost import (in this case > p.b) is completed, while sys.modules has the (incomplete) modules 'p', > 'p.a' and 'p.b', the attributes p.a and p.b aren't added until after > their import is completed. Which it isn't during recursive import. > Apparently 'from <anything> import <something>' looks for the > <something> attribute in the <parent> object. This is because > "from...import" can also be used to import objects other than modules > (e.g. "from M import C"). I'm guessing that setting the attribute is > delayed until the import is totally complete, because upon a failed > import we remove the half-imported module object from sys.modules, but > apparently we didn 't want to be in the business of removing the > attribute from the parent package, so that's only set after the import > is deemed successful. > > At least, this is my hypothesis, thinking about it -- I might look at > the code later. :-) > > The most portable solution is to avoid "from...import" and instead > write something like > > import p.b as b
So it turns out that "from X import Y" compiles into this bytecode: 0 LOAD_CONST 0 (-1) 3 LOAD_CONST 1 (('Y',)) 6 IMPORT_NAME 0 (X) 9 IMPORT_FROM 1 (Y) 12 STORE_NAME 1 (Y) 15 POP_TOP The first three opcodes (through IMPORT_NAME) call __import__('X', None, None, ('Y',)) and push the result on top of the stack; this result is the toplevel package X. The IMPORT_FROM opcode is essentially a getattr call that turns an AttributeError into an ImportError exception. I changed p/a.py into p = __import__('p', None, None, ['b']) print(p.b) and confirmed that it fails on the print() line in p.b. Does anyone feel that this ought to be fixed? -- --Guido van Rossum (home page: http://www.python.org/~guido/) _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com