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