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

--
http://mail.python.org/mailman/listinfo/python-list

Reply via email to