al*****@yahoo.com (Alex Martelli) writes:
SM <sj******@gmail.com> wrote:
al*****@yahoo.com (Alex Martelli) wrote in message
news:<1gn8ja3.7d3sbhuk94khN%al*****@yahoo.com>... If you need [classes] to be _updatable_ at runtime, look at a recipe by
Michael Hudson in the cookbook -- I've updated it for the printed
version 2nd ed (since we do have __subclasses__ now, yay!) but that's
not done yet. My vote for most useful custom metaclasses ever...
Wow, thanks :)
That recipe is here:
http://aspn.activestate.com/ASPN/Coo.../Recipe/160164
Is it correct that this metaclass solution does not handle changes to
__init__, including new attributes that are bound there? I.e., it
It doesn't rerun __init__ nor any other method on existing instances.
Well... it runs change_class on existing instances, but see below...
basically only deals with modification or addition or deletion of
methods; if you need to add new attributes or have any other new code
in __init__, you'll have to make new instances for all the old
instances, or deal with it some other way. In which case would you be
better off just using that other way from the start?
It's pretty trivial to enhance the recipe to run a per-instance or
per-subclass __make_old_into_new__ method, if that method exists, on all
existing old instances -- if you need to adjust the old instances'
states (==attributes), that strikes me as the best architecture.
I'd sort of thought about this when I wrote the recipe initially --
it's why there is a change_class method -- but now realize that it
doesn't really work, because when you reload the module, it runs the
*old* change_class when it would (obviously) be much more useful to
somehow run a new method.
How about this diff (from what's on the recipe page now):
*** autoreloader.py~ 2004-10-27 17:50:03.000000000 +0100
--- autoreloader.py 2004-11-26 11:36:45.000000000 +0000
***************
*** 27,33 ****
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
--- 27,34 ----
if d.has_key(name):
old_class = d[name]
for instance in old_class.__instances__():
! instance.__class__ = new_class
! instance.update_self()
new_class.__instance_refs__.append(
weakref.ref(instance))
# this section only works in 2.3
***************
*** 44,51 ****
class AutoReloader:
__metaclass__ = MetaAutoReloader
! def change_class(self, new_class):
! self.__class__ = new_class
class Bar(AutoReloader):
pass
--- 45,52 ----
class AutoReloader:
__metaclass__ = MetaAutoReloader
! def update_self(self):
! pass
class Bar(AutoReloader):
pass
***************
*** 67,69 ****
--- 68,94 ----
b2.meth(2)
# new Baz() instances now play too:
Baz().meth(3)
+
+ class C(AutoReloader):
+ def __init__(self, a):
+ self.a = 1
+ def get_attribute(self):
+ return self.a
+
+ c = C(1)
+
+ print c.get_attribute()
+
+ class C(AutoReloader):
+ def __init__(self, b):
+ self.b = b
+ def get_attribute(self):
+ return self.b
+
+ def update_self(self):
+ self.b = self.a
+ del self.a
+
+ print c.get_attribute()
+
+
Probably a bit more useful, though it has the disadvantage that it
will crash and burn if you forget to remove the update_self() method
before reloading again (that's probably inevitable, though). Maybe
you could introduce revision numbers on the instances and the classes
or something, though this might be getting a little complex.
Cheers,
mwh
--
Important data should not be entrusted to Pinstripe, as it may
eat it and make loud belching noises.
-- from the announcement of the beta of "Pinstripe" aka. Redhat 7.0