<div dir="ltr"><br><div class="gmail_extra"><br><br><div class="gmail_quote">On Thu, Apr 4, 2013 at 5:00 PM, PJ Eby <span dir="ltr"><<a href="mailto:pje@telecommunity.com" target="_blank">pje@telecommunity.com</a>></span> wrote:<br>

<blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex"><div class="im">On Thu, Apr 4, 2013 at 4:42 PM, Guido van Rossum <<a href="mailto:guido@python.org">guido@python.org</a>> wrote:<br>


> I do think it would be fine if "from a import b" returned the<br>
> attribute 'b' of module 'a' if it exists, and otherwise look for<br>
> module 'a.b' in sys.modules.<br>
<br>
</div>Technically, it already does that -- but inside of __import__, not in<br>
the IMPORT_FROM opcode.<br>
<br>
But then *after* doing that check-and-fallback, __import__ doesn't<br>
assign a.b, because it assumes the recursive import it called has<br>
already done this...</blockquote><div><br></div><div style>It's an unfortunate side-effect of having loaders set sys.modules for new modules not also set them as an attribute on their parent package immediately as well (or you could argue it's a side-effect of not passing in a module instead of a name to load_module() but that's another discussion).</div>

<div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">  which means that when __import__ returns, the<br>


IMPORT_FROM opcode tries and fails to do the getattr.<br>
<br>
This could be fixed in one of two ways.   Either:<br>
<br>
1. Change importlib._bootstrap._handle_fromlist() to set a.b if it<br>
successfully imports 'a.b' (inside its duplicate handling for what<br>
IMPORT_FROM does), or<br></blockquote><div><br></div><div style>It's three lines, one of which is 'else:'. Just did it.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">


2. Change the IMPORT_FROM opcode to handle the fallback itself</blockquote><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;padding-left:1ex">


<br>
While the latter involves a bit of C coding, it has fewer potential<br>
side-effects on the import system as a whole, and simply ensures that<br>
if "import" would succeed, then so would "from...import" targeting the<br>
same module.<br>
<br>
(There might be other fixes I haven't thought of, but really, changing<br>
IMPORT_FROM to fallback to a sys.modules check is probably by far the<br>
least-invasive way to handle it.)<br></blockquote><div><br></div><div>This is my preference as well. The change would be small: I think all you need to do is if the getattr() fails then fall back to sys.modules. Although if it were me and I was casting backwards-compatibility to the wind I would rip out the whole fromlist part of __import__() and let the bytecode worry about the fromlist, basically making the import opcode call importlib.import_module().<br>

</div><div><br></div></div></div></div>