Reload Tricks
Michael Spencer
mahs at telcopartners.com
Sat Jan 22 00:24:47 EST 2005
Kamilche wrote:
> I want my program to be able to reload its code dynamically. I have a
> large hierarchy of objects in memory. The inheritance hierarchy of
> these objects are scattered over several files.
>
> I find that after reloading the appropriate files, and overwriting the
> __class__ of object instances, one more thing is necessary: reloading
> the __bases__ of each reloaded class. If I don't do this, the modules
> reloaded first point to old versions of the classes from later modules,
> and when the later module is reloaded, it doesn't update the
> inheritance hierarchy of classes already loaded.
>
> This appears to be working... but now I'm wondering, what else did it
> not change? Can I expect more toes to be blown off?
>
> --Kamilche
>
There are some cases when re-assigning __class__ isn't possible, for example:
>>> class A(object):
... pass
...
>>> class B(dict):
... pass
...
>>> class C:
... pass
...
>>> a = A()
>>> a.__class__ = B
Traceback (most recent call last):
File "<input>", line 1, in ?
TypeError: __class__ assignment: 'A' object layout differs from 'B'
>>> a.__class__ = C
Traceback (most recent call last):
File "<input>", line 1, in ?
TypeError: __class__ must be set to new-style class, not 'classobj' object
>>>
An alternative approach (with some pros and cons) is to modify the class in
place, using something like:
>>> def reclass(cls, to_cls):
... """Updates attributes of cls to match those of to_cls"""
...
... DONOTCOPY = ("__name__","__bases__","__base__",
... "__dict__", "__doc__","__weakref__")
...
... fromdict = cls.__dict__
... todict = to_cls.__dict__
...
... # Delete any attribute present in the new class
... [delattr(cls,attr) for attr in fromdict.keys()
... if not((attr in todict) or (attr in DONOTCOPY)) ]
...
... for to_attr, to_obj in todict.iteritems():
...
... if to_attr in DONOTCOPY:
... continue
...
... # This overwrites all functions, even if they haven't changed.
... if type(to_obj) is types.MethodType:
... func = to_obj.im_func
... to_obj = types.MethodType(func,None, cls)
...
... setattr(cls, to_attr,to_obj)
...
>>> class A(object):
... attr = "A"
...
>>> class B(object):
... attr = "B"
...
>>> a = A()
>>> reclass(A,B)
>>> a.attr
'B'
>>>
This copies attributes of old and new-style classes (in fact anything with a
__dict__ so probably a module would work too)
You still run into problems trying to re-assigning __bases__ to incompatible
objects, but this one-attribute-at-a-time approach gives you the potential to
intercept problem cases. In the example above, problems are avoided by not
copying __bases__.
An additional advantage of this aprpoach is that you don't need to keep track of
class instances, in order to change their __class__. Instances automatically
acquire the new behavior
One wart is that class docstrings are not writeable, so cannot be copied. Why?
Michael
More information about the Python-list
mailing list