On Feb 27, 3:50 pm, "Ziga Seilnacht" <[EMAIL PROTECTED]> wrote: > Andrew Felch wrote: > > Hello all, > > > I'm using the metaclass trick for automatic reloading of class member > > functions, found > > at:http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/160164 > > > My problem is that if I > > 1) pickle an object that inherits from "AutoReloader" > > 2) unpickle the object > > 3) modify one of the pickled' object's derived class methods > > 4) reload the module holding the class > > > ... then the changes don't affect the unpickled object. If I unpickle > > the object again, of course the changes take effect. > > > My friend that loves Smalltalk is laughing at me. I thought I had the > > upperhand when I discovered the metaclasses but now I am not sure what > > to do. I really don't want to have to unpickle again, I'm processing > > video and it can take a long time. > > > By the way, I used to avoid all of these problems by never making > > classes, and always building complex structures of lists, > > dictionaries, and tuples with global functions. It's going to take me > > a while to kick those horrible habits (during my transition, I'm > > deriving from list, dict, etc. hehe), perhaps a link to the metaclass > > trick is in order in the tutorial's comments on reload? > > > Any help that avoids having to unpickle again is appreciated! > > > Thanks, > > Andrew Felch > > This happens because unpickling doesn't recreate your object by > calling its type. MetaInstanceTracker registers an instance only > when it is created by calling a class. > > You can solve this by moving the instance registration to > AutoReloader.__new__ and using pickle protocol version 2, but the > best solution is to avoid both pickle (old pickles break if you > change your code) and autoreloading (it's meant to be used in > interactive console and entertaining ircbots, not in normal code). > > Ziga- Hide quoted text - > > - Show quoted text -
Thanks Ziga. I use pickle protocol 2 and binary file types with the command: "cPickle.dump(obj, file, 2)" I did your suggestion, i commented out the "__call__" function of MetaInstanceTracker and copied the text to the __new__ function of AutoReloader (code appended). I got a crazy recursive error message (also appended below). In my code, I am creating a new instance, rather than using the pickled object (it needs to work in both modes). Thanks very much for helping me get through this. With my development approach, finding a solution to this problem is really important to me. ... File "C:\Python25\lib\site-packages\tdbu.py", line 67, in __new__ instance = super(MetaInstanceTracker, self).__call__(*args, **kw) File "C:\Python25\lib\site-packages\tdbu.py", line 67, in __new__ instance = super(MetaInstanceTracker, self).__call__(*args, **kw) File "C:\Python25\lib\site-packages\tdbu.py", line 67, in __new__ instance = super(MetaInstanceTracker, self).__call__(*args, **kw) File "C:\Python25\lib\site-packages\tdbu.py", line 67, in __new__ instance = super(MetaInstanceTracker, self).__call__(*args, **kw) File "C:\Python25\lib\site-packages\tdbu.py", line 67, in __new__ instance = super(MetaInstanceTracker, self).__call__(*args, **kw) File "C:\Python25\lib\site-packages\tdbu.py", line 67, in __new__ instance = super(MetaInstanceTracker, self).__call__(*args, **kw) RuntimeError: maximum recursion depth exceeded <code> import weakref, inspect class MetaInstanceTracker(type): def __new__(cls, name, bases, ns): t = super(MetaInstanceTracker, cls).__new__(cls, name, bases, ns) t.__instance_refs__ = [] return t def __instances__(self): instances = [(r, r()) for r in self.__instance_refs__] instances = filter(lambda (x,y): y is not None, instances) self.__instance_refs__ = [r for (r, o) in instances] return [o for (r, o) in instances] ## def __call__(self, *args, **kw): ## instance = super(MetaInstanceTracker, self).__call__(*args, **kw) ## self.__instance_refs__.append(weakref.ref(instance)) ## return instance class InstanceTracker: __metaclass__ = MetaInstanceTracker class MetaAutoReloader(MetaInstanceTracker): def __new__(cls, name, bases, ns): new_class = super(MetaAutoReloader, cls).__new__( cls, name, bases, ns) f = inspect.currentframe().f_back for d in [f.f_locals, f.f_globals]: if d.has_key(name): old_class = d[name] for instance in old_class.__instances__(): instance.change_class(new_class) new_class.__instance_refs__.append( weakref.ref(instance)) # this section only works in 2.3 for subcls in old_class.__subclasses__(): newbases = () for base in subcls.__bases__: if base is old_class: newbases += (new_class,) else: newbases += (base,) subcls.__bases__ = newbases break return new_class class AutoReloader: __metaclass__ = MetaAutoReloader def change_class(self, new_class): self.__class__ = new_class def __new__(self, *args, **kw): instance = super(MetaInstanceTracker, self).__call__(*args, **kw) self.__instance_refs__.append(weakref.ref(instance)) return instance Thanks, Andrew Felch -- http://mail.python.org/mailman/listinfo/python-list