python中object如何更改_在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

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

解决方案

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:

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

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:

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)

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)

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值