比方说,你有一个从一个模块内的类实例化一个对象。 现在,你重新加载模块。 你想这样做的下一件事是做出重装影响类。
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
你必须做出一个新的ClassChange对象,复制myObject的成,并删除旧的myObject的? 还是有更简单的方法?
编辑:run()方法似乎是一个静态类风格的方法,但也仅仅是为了简洁起见。 我想的run()方法来对物体内部的数据进行操作,所以静态模块功能不会做......
要更新类的所有实例,有必要保持对那些情况下轨道的地方 - 通常是通过弱引用(弱值字典是最方便和一般),因此“跟踪”功能将不消失停止不需要的情况下,当然!
通常你会想保持这样的容器类对象,但是,在这种情况下,你会被重新加载模块,让旧的类对象是不平凡的; 这是简单的模块级工作。
所以,让我们说这是一个“升级模块”需要定义,在其开始,弱值字典(和辅助“下一个键使用” INT)用,比如,常规的名字:
import weakref
class _List(list): pass # a weakly-referenceable sequence
_objs = weakref.WeakValueDictionary()
_nextkey = 0
def _register(obj):
_objs[_nextkey] = List((obj, type(obj).__name__))
_nextkey += 1
模块中的每个类都必须有,一般在__init__
,呼叫_register(self)
注册新的实例。
现在的“重装功能”可以通过获取副本获得此模块中的所有类的所有实例的名册_objs
它重新加载模块之前。
如果这是需要的所有是更改代码 ,那么生活是相当容易:
def reload_all(amodule):
objs = getattr(amodule, '_objs', None)
reload(amodule)
if not objs: return # not an upgraable-module, or no objects
newobjs = getattr(amodule, '_objs', None)
for obj, classname in objs.values():
newclass = getattr(amodule, classname)
obj.__class__ = newclass
if newobjs: newobjs._register(obj)
唉,一个通常不希望给新类有机会更精细的老类的一个对象升级到自身,例如,通过合适的类方法。 这不是太难之一:
def reload_all(amodule):
objs = getattr(amodule, '_objs', None)
reload(amodule)
if not objs: return # not an upgraable-module, or no objects
newobjs = getattr(amodule, '_objs', None)
for obj, classname in objs:
newclass = getattr(amodule, classname)
upgrade = getattr(newclass, '_upgrade', None)
if upgrade:
upgrade(obj)
else:
obj.__class__ = newclass
if newobjs: newobjs._register(obj)
例如,假设类扎普的新版本已经改名,从foo到酒吧的属性。 这可能是新的Zap的代码:
class Zap(object):
def __init__(self):
_register(self)
self.bar = 23
@classmethod
def _upgrade(cls, obj):
obj.bar = obj.foo
del obj.foo
obj.__class__ = cls
这还不是全部 - 还有很多更多的话要说 - 但是,它的要点,并回答是足够WAY已久的(和我,用尽足够;-)。
你必须做一个新的对象。 有没有办法神奇地更新现有的对象。
阅读reload
内置文档 -这是很清楚的。 这里的最后一段:
如果一个模块实例化一个类的实例,重装定义类不会影响实例的方法定义的模块-他们继续使用旧的类定义。 这同样适用于派生类如此。
有文档中的其他注意事项,让您真正应该看它,并考虑替代方案。 也许你要开始与你为什么要使用一个新的问题, reload
,并要求获得同样的事情的其他方式。
我对这种做法如下:
- 翻阅所有导入模块,只有重装那些具有新的.py文件(相对于现有的.pyc文件的文件)
- 对于每一个函数和类方法被重新装载,设置old_function .__ code__ = new_function .__ code__。
- 对于每一个重载类,使用gc.get_referrers列出的类的实例及其__class__属性设置为新版本。
优点这种方法是:
- 通常无需重新加载任何特定的顺序模块
- 通常只需要重新加载与改变的代码,并没有更多的模块
- 不需要修改类来跟踪他们的实例
你可以阅读有关的技术(及其局限性)位置: http://luke-campagnola.blogspot.com/2010/12/easy-automated-reloading-in-python.html
你可以在这里下载代码: http://luke.campagnola.me/code/downloads/reload.py
你必须得到新鲜的模块新的类并为其分配回实例。
如果你能触发该操作在你使用的实例与此混入:
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)
下面的代码你想要做什么,但请不要使用它 (至少是在你很确定你做正确的事), 我张贴这只是为了说明目的 。
mymodule.py:
class ClassChange():
@classmethod
def run(cls,instance):
print 'one',id(instance)
myexperiment.py:
import mymodule
myObject = mymodule.ClassChange()
mymodule.ClassChange.run(myObject)
# change mymodule.py here
reload(mymodule)
mymodule.ClassChange.run(myObject)
当您的代码实例化myObject
,你得到的一个实例ClassChange
。 这种情况下有一个名为实例方法 run
。 该对象保持这种实例方法(通过nosklo解释的原因),即使重装时,因为重装只有重新加载类 ClassChange
。
在我上面的代码 , run
是一个类的方法 。 类的方法总是难免和类,而不是实例(这就是为什么他们的第一个参数通常被称为操作cls
,而不是self
)。 德恩ClassChange
被重新加载,所以是这个类的方法。
你可以看到,我还通过实例作为参数与ClassChange的正确的(相同的)情况下工作。 你可以看到,由于相同的对象ID在这两种情况下打印。
我不知道这是否是做的最好的办法,或者你想要做什么......网格但这可能会为你工作。 如果你想改变一个方法的行为,对于某些类型的所有对象...只需使用一个函数变量。 例如:
def default_behavior(the_object):
print "one"
def some_other_behavior(the_object):
print "two"
class Foo(object):
# Class variable: a function that has the behavior
# (Takes an instance of a Foo as argument)
behavior = default_behavior
def __init__(self):
print "Foo initialized"
def method_that_changes_behavior(self):
Foo.behavior(self)
if __name__ == "__main__":
foo = Foo()
foo.method_that_changes_behavior() # prints "one"
Foo.behavior = some_other_behavior
foo.method_that_changes_behavior() # prints "two"
# OUTPUT
# Foo initialized
# one
# two
现在,您可以有一个类,负责重新加载模块,并重新加载后,设置Foo.behavior
到新的东西。 我尝试了这种代码。 它工作正常:-)。
这是否为您工作?
有技巧,让你想要什么可能。
有人已经提到,你可以有信守实例列表的类,然后改变类的每个实例,以重新加载时新的。
然而,这是没有效率的。 更好的方法是改变旧的类,以便它是一样的新类。