Reputation: 53
I'm find a way to reload the method of a class object at runtime,here is the example: I have define a class A firstly which lies on the file test.py.
class A:
def __init_(self):
pass
def Message(self):
print "1"
then I start Python shell in the linux, and execute the following code:
>>> from test import A
>>> a = A()
>>> a.Message()
1
Now I vi the test.py in the fly, and change the method "Message":
class A:
def __init_(self):
pass
def Message(self):
print "2"
but when I execute the a.Message() in the Python shell, the result is always the "1" and not "2"
How I write the code to make the object 'a.Message' to execute the updated code.
Thank you very much!
chu
Upvotes: 5
Views: 7549
Reputation: 1580
The question formulates a powerful tool I frequently use when developing and experimenting with new ideas on architecture and algorithms for python and wish to reload specific implementations without disturbing current locals.
I use a simplistic approach of
importlib.reload(my_module)
my_instance.my_method = types.MethodType(my_class.my_method, my_instance)
my_module has been pared down to only define function and class implementations. For the few creation of global values at a module level that I have, I include those in other modules so they do not get clobbered on reload as importlib.reload only does a shallow reload.
I have some utility functions specific for my working style that uses the above technique in facilitating reloading of modules, classes and functions that I list.
This approach helps me more explicitly see how I'm modifying my runtime logic when I do so. iPython does similar things and has similar goals as the above, but for my purposes it is too magical, bloated and poorly designed, with its API thinly documented. It is far too logically coupled with jupyter and it feels like the expectation of it API designers is that the API will never be used outside of that context so no effort has been made in proper abstractions - a rather self fulfilling prophecy.
Upvotes: 1
Reputation: 2979
I've just spend a while trying to solve this issue myself and ended up with a slightly different solution to the others suggested here. I've put it in a gist with plenty of comments, but as is the SO way I'll give a brief explantion here:
Rather than modify individual instances of an old version of a class, or copy them into new instances of the new class, the idea is to set the methods of the old class (i.e. the attributes of the class itself not the instances of the class) to be the updated methods from the new class. It also takes care of chaining back over multiple versions of the class.
Upvotes: 3
Reputation: 63
You have to reload your module from the fresh code, get the class and assign it back to the instance:
import sys
def update_class(instance):
cls=instance.__class__
modname=cls.__module__
del sys.modules[modname]
module=__import__(modname)
instance.__class__=getattr(module,cls.__name__)
While developing and updating the code you could use the same trick to define instances that reload their class anytime they are used.
import sys
class ObjDebug(object):
def __getattribute__(self,k):
ga=object.__getattribute__
sa=object.__setattr__
cls=ga(self,'__class__')
modname=cls.__module__
mod=__import__(modname)
del sys.modules[modname]
reload(mod)
sa(self,'__class__',getattr(mod,cls.__name__))
return ga(self,k)
class A(ObjDebug):
pass
a=A()
If you edit the code of A to add a method, then you can use it without instantiating again a.
Actually del sys.modules[modname]
seems to create nasty bugs for which some symbols becomes None objects from one line to the other. (not understood why)
Upvotes: 2
Reputation: 601421
To relaod your module in the interactive interpreter, you can use
import test
reload(test)
from test import A
But this won't affect instance of A
which already exist -- they will still be of the old type A
, hence having the old method. I think it is not possible to change existing instances, nor do I think it is a good idea.
By the way, I would recommend using IPython for code testing. It facilitates recursive reload using the %reload
magic, and (even more useful) the %run
magic to test modules.
Upvotes: 4