Automatic reloading, metaclasses, and pickle
Ziga Seilnacht
ziga.seilnacht at gmail.com
Tue Feb 27 17:30:26 EST 2007
Andrew Felch wrote:
>
> 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.
Here is a version that should work. It should work with all protocols,
see InstanceTracker.__reduce_ex__. Note that all subclasses of
InstanceTracker and AutoReloader should be cautious when overriding
the
__new__ method. They must call their base class' __new__ method,
preferably by using super(), or the tracking won't work.
# adapted from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/160164
import weakref, inspect
class MetaInstanceTracker(type):
def __init__(cls, name, bases, ns):
super(MetaInstanceTracker, cls).__init__(name, bases, ns)
cls.__instance_refs__ = []
def __instances__(cls):
instances = []
validrefs = []
for ref in cls.__instance_refs__:
instance = ref()
if instance is not None:
instances.append(instance)
validrefs.append(ref)
cls.__instance_refs__ = validrefs
return instances
class InstanceTracker(object):
__metaclass__ = MetaInstanceTracker
def __new__(*args, **kwargs):
cls = args[0]
self = super(InstanceTracker, cls).__new__(*args, **kwargs)
cls.__instance_refs__.append(weakref.ref(self))
return self
def __reduce_ex__(self, proto):
return super(InstanceTracker, self).__reduce_ex__(2)
class MetaAutoReloader(MetaInstanceTracker):
def __init__(cls, name, bases, ns):
super(MetaAutoReloader, cls).__init__(name, bases, ns)
f = inspect.currentframe().f_back
for d in [f.f_locals, f.f_globals]:
if name in d:
old_class = d[name]
for instance in old_class.__instances__():
instance.change_class(cls)
cls.__instance_refs__.append(weakref.ref(instance))
for subcls in old_class.__subclasses__():
newbases = []
for base in subcls.__bases__:
if base is old_class:
newbases.append(cls)
else:
newbases.append(base)
subcls.__bases__ = tuple(newbases)
break
class AutoReloader(InstanceTracker):
__metaclass__ = MetaAutoReloader
def change_class(self, new_class):
self.__class__ = new_class
Ziga
More information about the Python-list
mailing list