Thursday, October 21, 2004

Metaclass to autoupdate existing instances of a class to newly modified and reloaded classes

This post is about this link


Pretty simple yet so powerfull:
ideas:
-name the class __metaclass__ so all we need is import
-keep track of the instances in a new key (A) of the class attributes dictionary
(use instance __init__ to add the new instances to A in the class)
-at module reload, check sys.modules for the old class and copy A from old class
to new class dictionary
-for each instance (a) in A replace a.__class__ from old class to new class


#----- autoupdate.py
'''metaclass for auto-update classes'''
class __metaclass__(type):
# automatically keeps tracks of instances
def __new__(cls, class_name, bases, class_dict):
import inspect
module_name = class_dict['__module__']
#we will update bellow the class_dict with a new key:
#instance_dict_name and value a list of instances

instance_dict_name = '_%s__instances' % class_name
# see if there is already an older class
import sys
old_instance_dict = None
if sys.modules.has_key(module_name):
module = sys.modules[module_name]
if hasattr(module, class_name):
old_instance_dict = getattr(getattr(module, class_name),
instance_dict_name)
# add instance list
import weakref
class_dict[instance_dict_name] = weakref.WeakValueDictionary()
# override the __init__
if class_dict.has_key('__init__'):
def new_init(self, *args, **kw):
instance_dict_name = '_%s__instances' % (
self.__class__.__name__)
getattr(self.__class__,
instance_dict_name)[id(self)] = self
self.__original_init__(*args, **kw)
class_dict['__original_init__'] = class_dict['__init__']
class_dict['__init__'] = new_init
else:
def new_init(self, *args, **kw):
instance_dict_name = '_%s__instances' % (
self.__class__.__name__)
getattr(self.__class__,
instance_dict_name)[id(self)] = self
class_dict['__init__'] = new_init
# build the class, with instance_dict
new_class = type.__new__(cls, class_name, bases, class_dict)
# copy over the instance dictionary, and update __class__
if old_instance_dict is not None:
for instance_id, instance in (
old_instance_dict.iteritems()):
getattr(new_class,
instance_dict_name)[instance_id] = instance
instance.__class__ = new_class
# return new class
return new_class

#----- Spam.py
from autoupdate import __metaclass__
class Egg:
'''Put here your class code'''
# def print(self):
# print 'Hello World!'

#----- from your Python console
import Spam
x = Spam.Egg()
# ... edit your Spam.py file and change code for Spam.Egg class,
# e.g.: add a print() method to Spam.Egg by uncommenting
# the corresponding lines. Save the file.
reload(Spam)
x.print() # prints 'Hello World!'

0 Comments:

Post a Comment

<< Home