在Python中,如何在重新加载后更改实例化的对象? [英] In Python, how do you change an instantiated object after a reload?

查看:467
本文介绍了在Python中,如何在重新加载后更改实例化的对象?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

比方说,您有一个从模块内部的类实例化的对象. 现在,您重新加载该模块. 接下来要做的是使重载影响该类.

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

是否必须创建一个新的ClassChange对象,将myObject复制到该对象中,然后删除旧的myObject?还是有更简单的方法?

Do you have to make a new ClassChange object, copy myObject into that, and delete the old myObject? Or is there a simpler way?

run()方法看起来像是静态类样式方法,但这只是为了简洁.我希望run()方法可以在对象内部的数据上进行操作,因此静态模块功能将无法执行...

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

推荐答案

要更新一个类的所有实例,必须跟踪那些实例的某个位置-通常通过弱引用(弱值dict是最方便和通用的)因此,跟踪"功能当然不会阻止不需要的实例消失!

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.

因此,假设可升级模块"在开始时需要使用常规名称来定义一个弱值字典(以及要使用的辅助下一个要使用的下一个键" int)

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:

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)才能注册新实例.

Each class in the module must have, typically in __init__, a call _register(self) to register new instances.

现在,重新加载功能"可以通过在重新加载模块之前获取_objs的副本来获取此模块中所有类的所有实例的花名册.

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.

如果只需要更改 code ,那么生活就很简单了:

If all that's needed is to change the code, then life is reasonably easy:

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)

las,通常确实希望给新类别一个机会,将旧类别的对象更精细地升级到自身,例如,通过合适的类方法.也不是很难:

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:

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)

例如,假设新版本的Zap类将属性从foo重命名为bar.这可能是新Zap的代码:

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:

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

这还不是全部-在这个问题上还有很多话要说-但是,要点在于,答案已经足够长了(我已经筋疲力尽;-).

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;-).

这篇关于在Python中,如何在重新加载后更改实例化的对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆