简体   繁体   中英

How to reload the code of a method of class object in Python?

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

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.

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)

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 (ie 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.

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM