'reload M' doesn't update 'from M inport *'

Frederic Rentsch anthra.norell at bluewin.ch
Fri Jul 9 14:38:43 EDT 2010


On Fri, 2010-07-09 at 15:58 +0000, Steven D'Aprano wrote:
> On Fri, 09 Jul 2010 15:02:25 +0200, Frederic Rentsch wrote:
> 
> > I develop in an IDLE window.
> > 
> > Module M says 'from service import *'. Next I correct a mistake in
> > function 'service.f'. Now 'service.f' works fine.
> 
> from service import *
> 
> should be considered advanced functionality that is discouraged unless 
> you really know what you are doing, precisely for the problems you are 
> experiencing. You should try to avoid it.
> 
> But putting that aside, if you have done "from service import *" in 
> module m, where are you getting "service.f" from? The only way that is 
> possible is if you ALSO say "import service".
> 
> 
> > I do 'reload (service); reload (M)'.
> > The function 'M.f' still misbehaves.
> > 
> > 'print inspect.getsource (service.f)' and 'print inspect.getsource
> > (M.f)' shows the same corrected code.
> 
> inspect.getsource always looks at the source code on disk, no matter what 
> the byte code in memory actually says.
> 
> > 'print service.f' and 'print M.f' show different ids.
> > 
> > So I do 'del M; reload (M)'. Nothing changes.
> > 
> > I delete M again and run gc.collect () to really clean house. I reload M
> > again and still nothing changes. The id of the reloaded function 'M.f'
> > is still the same as it was before the purge and so M.f still isn't
> > fixed.
> >
> > I know I have more radical options, such as starting a new IDLE window.
> > That would save me time, but I'd like to take the opportunity to
> > understand what is happening. Surely someone out there knows.
> 
> Yes. You have to understand importing. Let's start with the simple:
> 
> import m
> 
> In *very* simplified pseudo-code, this does:
> 
> look for module m in the global cache
> if not there, then:
>     search for m.py
>     compile it to a Module object
>     put the Module object in the cache
> create a new name "m" in the local namespace
> set the name "m" to the Module object in the cache
> 
> Now let's compare it to:
> 
> from m import f
> 
> look for module m in the global cache
> if not there, then:
>     search for m.py
>     compile it to a Module object
>     put the Module object in the cache
> look for object named "f" in the Module object
> create a new name "f" in the local namespace
> set the name "f" to cached object
> 
> The important thing to notice is the the name "f" is a local variable. It 
> doesn't, and can't, remember that it comes from module m. Reloading m 
> can't do anything to f, because the connection is lost.
> 
> Now consider that the object "f" that came from m was itself imported 
> from another module, "service". Reloading service doesn't help, because 
> m.f doesn't know it came from service. Reloading m doesn't help, because 
> all that does is run "from service import f" again, and that just fetches 
> f from the global cache.
> 
> The simplest, easiest way of dealing with this is not to have to deal 
> with it: don't use "from service import f", and ESPECIALLY don't use 
> "from service import *". Always use fully-qualified importing:
> 
> import service
> service.f
> 
> Now "reload(service)" should do what you expect.
> 
> The other way is not to bother with reload. It's not very powerful, only 
> good for the simplest use in the interactive interpreter. Just exit the 
> interpreter and restart it.
> 
> 
> -- 
> Steven

Thank you very much for your excellent explanation!
   I must say that I haven't been using the "from soandso import ..."
formula at all. I thought it might expose names to collision, and why
should I assume the responsibility if I can avoid the problem altogether
using explicit names. If I used the, shall we say, "direct import" this
time it was in an effort to develop a more extensive program. I thought
if a module grows beyond a size that's comfortable to edit, I could just
move select segments to separate files and replace the vacancy with
"from the_respective_segment_module import *", analogous to "#include"
in C.
   The remedy seems to have side-effects that can kill the patient. So
I'll go back to the explicit imports, then. No problem at all. 

Thanking you and the other helpers too

Frederic





More information about the Python-list mailing list