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

Reply via email to