Let's say you have an object that was instantiated from a class inside a module. Now, you reload that module. The next thing you'd like to do is make that reload affect that class.
mymodule.py
---
class ClassChange():
def run(self):
print 'one'
myexperiment.py
---
import mymodule
from mymodule import ClassChange # why is this necessary?
myObject = ClassChange()
myObject.run()
>>> one
### later, i changed this file, so that it says print 'two'
reload(mymodule)
# trick to change myObject needed here
myObject.run()
>>> two
Do you have to make a new ClassChange object, copy myObject into that, and delete the old myObject? Or is there a simpler way?
Edit: The run() method seems like a static class style method but that was only for the sake of brevity. I'd like the run() method to operate on data inside the object, so a static module function wouldn't do...
My approach to this is the following:
Advantages to this approach are:
You can read about the technique (and its limitations) here: http://luke-campagnola.blogspot.com/2010/12/easy-automated-reloading-in-python.html
And you can download the code here: http://luke.campagnola.me/code/downloads/reload.py
The following code does what you want, but please don't use it (at least not until you're very sure you're doing the right thing), I'm posting it for explanation purposes only.
mymodule.py:
myexperiment.py:
When in your code you instanciate
myObject
, you get an instance ofClassChange
. This instance has an instance method calledrun
. The object keeps this instance method (for the reason explained by nosklo) even when reloading, because reloading only reloads the classClassChange
.In my code above,
run
is a class method. Class methods are always bound to and operate on the class, not the instance (which is why their first argument is usually calledcls
, notself
). WennClassChange
is reloaded, so is this class method.You can see that I also pass the instance as an argument to work with the correct (same) instance of ClassChange. You can see that because the same object id is printed in both cases.
There are tricks to make what you want possible.
Someone already mentioned that you can have a class that keeps a list of its instances, and then changing the class of each instance to the new one upon reload.
However, that is not efficient. A better method is to change the old class so that it is the same as the new class.
I'm not sure if this is the best way to do it, or meshes with what you want to do... but this may work for you. If you want to change the behavior of a method, for all objects of a certain type... just use a function variable. For example:
You can now have a class that is responsible for reloading modules, and after reloading, setting
Foo.behavior
to something new. I tried out this code. It works fine :-).Does this work for you?
You have to make a new object. There's no way to magically update the existing objects.
Read the
reload
builtin documentation - it is very clear. Here's the last paragraph:There are other caveats in the documentation, so you really should read it, and consider alternatives. Maybe you want to start a new question with why you want to use
reload
and ask for other ways of achieving the same thing.To update all instances of a class, it is necessary to keep track somewhere about those instances -- typically via weak references (weak value dict is handiest and general) so the "keeping track" functionality won't stop unneeded instances from going away, of course!
You'd normally want to keep such a container in the class object, but, in this case, since you'll be reloading the module, getting the old class object is not trivial; it's simpler to work at module level.
So, let's say that an "upgradable module" needs to define, at its start, a weak value dict (and an auxiliary "next key to use" int) with, say, conventional names:
Each class in the module must have, typically in
__init__
, a call_register(self)
to register new instances.Now the "reload function" can get the roster of all instances of all classes in this module by getting a copy of
_objs
before it reloads the module.If all that's needed is to change the code, then life is reasonably easy:
Alas, one typically does want to give the new class a chance to upgrade an object of the old class to itself more finely, e.g. by a suitable class method. That's not too hard either:
For example, say the new version of class Zap has renamed an attribute from foo to bar. This could be the code of the new Zap:
This is NOT all -- there's a LOT more to say on the subject -- but, it IS the gist, and the answer is WAY long enough already (and I, exhausted enough;-).