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

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Fri Jul 9 11:58:38 EDT 2010


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



More information about the Python-list mailing list