a class auto upgrader

Michael Hudson mwh at python.net
Thu Oct 31 15:42:45 CET 2002


Michael Hudson <mwh at python.net> writes:

> I'm on my way out, so I don't really have time to explain this, but
> here's a little something that may ease interactive development with
> Python.

Here's a better version of what I had before.

It doesn't interact well with inheritance (see comments at the end),
and there's not a lot I can do about that, because the __bases__
attribute of new style classes is not mutable.  This might change in
Python 2.3...

hey-i-don't-care-if-noone's-listening,-i-think-it's-neat-ly y'rs
M.

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))
                break
        return new_class

class AutoReloader:
    __metaclass__ = MetaAutoReloader
    def change_class(self, new_class):
        self.__class__ = new_class

class Bar(AutoReloader):
    pass

class Baz(Bar):
    pass

b = Bar()
b2 = Baz()

class Bar(AutoReloader):
    def meth(self, arg):
       print arg

if __name__ == '__main__':
    # now b is "upgraded" to the new Bar class:
    b.meth(1)
    # unfortunately, Baz instances can't join the fun:
    try:
        b2.meth()
    except AttributeError:
        print "nuts"
    # even worse (and, actually, harder to deal with):
    # new Baz() instances can't play either:
    # unfortunately, Baz instances can't join the fun:
    try:
        Baz().meth()
    except AttributeError:
        print "nuts again"

-- 
  I've even been known to get Marmite *near* my mouth -- but never
  actually in it yet.  Vegamite is right out.
 UnicodeError: ASCII unpalatable error: vegamite found, ham expected
                                       -- Tim Peters, comp.lang.python



More information about the Python-list mailing list