如何在Python中重新加载类对象的方法代码?
我在找一种方法,可以在程序运行时重新加载一个类对象的方法。这里有个例子:
我首先定义了一个类A,这个类在文件test.py里。
class A:
def __init_(self):
pass
def Message(self):
print "1"
然后我在Linux中启动了Python的命令行,执行了以下代码:
>>> from test import A
>>> a = A()
>>> a.Message()
1
现在我在运行时打开test.py文件,修改了方法“Message”:
class A:
def __init_(self):
pass
def Message(self):
print "2"
但是当我在Python命令行中执行a.Message()时,结果总是“1”,而不是“2”。
我该怎么写代码,让对象'a.Message'执行更新后的代码呢?
非常感谢!
chu
4 个回答
你需要从新的代码中重新加载你的模块,获取类并把它重新分配给实例:
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__)
在开发和更新代码时,你可以使用同样的方法来定义实例,这样它们在每次使用时都会重新加载它们的类。
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()
如果你修改了A的代码,添加了一个方法,那么你可以直接使用这个方法,而不需要重新创建一个新的实例a。
实际上,del sys.modules[modname]
似乎会导致一些麻烦的错误,导致某些符号在一瞬间变成了None对象。(具体原因不太明白)
我刚花了一段时间自己解决这个问题,最后得到了一个和这里其他人建议的稍微不同的解决方案。我把它放在了一个gist上,并加了很多注释,不过按照StackOverflow的风格,我在这里简单解释一下:
与其去修改旧版本类的每一个实例,或者把它们复制到新版本类的新实例中,不如直接把旧类的方法(也就是类本身的属性,而不是类的实例)替换成新类的更新方法。这样做还可以处理多个版本类之间的继承关系。
要在交互式解释器中重新加载你的模块,可以使用
import test
reload(test)
from test import A
但是,这样做不会影响已经存在的 A
实例——它们仍然是旧类型的 A
,所以还是会使用旧的方法。我觉得改变已经存在的实例是不可能的,也不是个好主意。
顺便提一下,我推荐使用 IPython 来测试代码。它可以方便地使用 %reload
这个魔法命令进行递归加载,更有用的是可以用 %run
这个魔法命令来测试模块。