在Python中,如何在重新加载后更改实例化对象?
假设您有一个从模块内的类实例化的对象。 现在,您重新加载该模块。 您要做的下一件事是使重新加载影响该类。
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() 方法对对象内部的数据进行操作,因此静态模块函数不会这样做......
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...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(8)
要更新类的所有实例,有必要在某个地方跟踪这些实例——通常通过弱引用(弱值字典是最方便和通用的),因此“跟踪”功能不会阻止不需要的实例消失,当然!
您通常希望在类对象中保留这样的容器,但是,在这种情况下,由于您将重新加载模块,因此获取旧的类对象并不简单; 在模块级别工作更简单。
因此,假设一个“可升级模块”需要在开始时定义一个弱值字典(以及一个辅助的“下一个要使用的键”int),并带有常规名称:
模块中的每个类通常必须具有在
__init__
中,调用_register(self)
来注册新实例。现在,“重新加载函数”可以在重新加载模块之前通过获取
_objs
的副本来获取该模块中所有类的所有实例的名册。如果所需要的只是更改代码,那么生活相当容易:
唉,人们通常确实希望给新类一个机会将旧类的对象更精细地升级为自身,例如通过合适的类方法。 这也不是太难:
例如,假设类 Zap 的新版本已将属性从 foo 重命名为 bar。 这可能是新 Zap 的代码:
这还不是全部——关于这个主题还有很多话要说——但是,这是要点,答案已经足够长了(而且我已经筋疲力尽了;- )。
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;-).
你必须创建一个新对象。 没有办法神奇地更新现有对象。
阅读
reload
内置文档 - 它非常清楚。 这是最后一段:文档中还有其他警告,因此您确实应该阅读它,并考虑替代方案。 也许您想开始一个新问题,询问为什么要使用
reload
,并询问实现相同目标的其他方法。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.我的方法如下:
这种方法的优点是:
您可以阅读有关该技术的信息(以及它的局限性)在这里:
http://luke-campagnola.blogspot.com /2010/12/easy-automated-reloading-in-python.html
您可以在这里下载代码:
http://luke.campagnola.me/code/downloads/reload.py
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
您必须从新模块中获取新类并将其分配回实例。
如果您可以在使用带有此 mixin 的实例时随时触发此操作:
You have to get the new class from the fresh module and assign it back to the instance.
If you could trigger this operation anytime you use an instance with this mixin:
以下代码可以实现您想要的功能,但是请不要使用它(至少在您非常确定自己做的是正确的事情之前不要使用它),我将其发布用于仅用于解释目的。
mymodule.py:myexperiment.py
:
当在代码中实例化
myObject
时,您将获得ClassChange
的实例。 该实例有一个名为run
的实例方法。 即使在重新加载时,该对象也会保留此实例方法(原因由 nosklo 解释),因为重新加载只会重新加载类ClassChange
。在上面的我的代码中,
run
是一个类方法。 类方法始终绑定到类(而不是实例)并对其进行操作(这就是为什么它们的第一个参数通常称为cls
,而不是self
)。 WennClassChange
被重新加载,这个类方法也是如此。您可以看到,我还将实例作为参数传递,以使用正确(相同)的 ClassChange 实例。 您可以看到这一点,因为在这两种情况下都打印了相同的对象 ID。
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.
我不确定这是否是最好的方法,或者是否符合您想要做的事情......但这可能对您有用。 如果您想更改某个方法的行为,对于某种类型的所有对象......只需使用函数变量即可。 例如:
您现在可以有一个类负责重新加载模块,并在重新加载后将 Foo.behavior 设置为新的内容。 我尝试了这段代码。 它工作正常:-)。
这对你有用吗?
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?
有一些技巧可以让你想要的事情成为可能。
有人已经提到,您可以拥有一个保留其实例列表的类,然后在重新加载时将每个实例的类更改为新实例。
然而,这效率不高。 更好的方法是更改旧类,使其与新类相同。
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.
这是 Python 3 的 @riccardo 答案的一个版本,并附有示例。
请注意,我们不需要
del sys.modules[modname]
,这实际上会导致错误。ObjDebug.py
示例:
MyClass.py
Python 控制台
Here is a version of @riccardo answer for Python 3, with an example.
Notice we don't need the
del sys.modules[modname]
, which in fact will result in an error.ObjDebug.py
Example:
MyClass.py
Python console