Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

having a function called after the constructor/__init__ is done

6 views
Skip to first unread message

thomas...@gmail.com

unread,
Mar 16, 2009, 11:11:18 PM3/16/09
to
Hi all,

We've been breaking our heads over a good way of accomplishing an
"on_load" event in our multitouch GUI frameowork PyMT. We think we'd
like to trigger an "on_load" event after a class is fully instantiated
(or just a function call for simplicity, so you dont need to worry
about our specific system). This is so that if I make a subclass of
some widget, I dont have to overwrite the __init__ method (use super,
know the args, and pass them) everytime. Maybe I just want to do some
really basic stuff that doesn't really have anything to do with the
parent class.

Anyway. My first attempt was to simply put a call to self.on_load at
the end of the widget base class. This doesn't work though, because,
if I subclass it and do things after the call to super.__init__,
on_load will be called before the constructor finishes (when the top
most parent class __init__ finishes)

We've sort of managed to achieve this by using a decorator that
changes the __init__ function. but even this doesnt seem like the
best way to do this. a) I now have to decorate every constructor i
ever write. b) it seems impossible to make it so that it only happens
once after the object is actually instantiated (since i have a
decorator on all my constructors..each constructor in the inheritance
line will call on_load once)

Can I do something fancy with metaclasses here? I think I could kind
of do this by making all my classes use __new__, and then essentially
use __init__ as what i want on_load to be...but that just seems really
nasty and unpythonic. not to speak about the confusion it would cause
with people trying to figure out the library.

So any ideas on how to get a function called on an object just after
__init__ is done executing?

Armin Moradi

unread,
Mar 16, 2009, 11:45:16 PM3/16/09
to alex goretoy, pytho...@python.org
class MyClass(object):
def __init__(self, really_init=True):
self.a = 3
self.b = 4
# other initialization
if really_init: on_load()

def on_load(self):
print 'hello!'

class B(MyClass):
def __init__(self):
super(B, self).__init__(False)
self.c = 4
print "B initialized"
MyClass.on_load()

def on_load(self):
print 'hello!'


Would this work?

(posted it again to include the python-list in To:)

--
Armin Moradi

Steven D'Aprano

unread,
Mar 16, 2009, 11:55:01 PM3/16/09
to
On Mon, 16 Mar 2009 20:11:18 -0700, thomas...@gmail.com wrote:

> Hi all,
>
> We've been breaking our heads over a good way of accomplishing an
> "on_load" event in our multitouch GUI frameowork PyMT. We think we'd
> like to trigger an "on_load" event after a class is fully instantiated

...


> Can I do something fancy with metaclasses here?

class MetaLoad(type):
def __new__(cls, name, bases, dict):
obj = type.__new__(cls, name, bases, dict)
return obj
def __call__(cls, *args, **kwargs):
instance = super(MetaLoad, cls).__call__(*args, **kwargs)
instance.on_load()
return instance

class Parrot(object):
__metaclass__ = MetaLoad
def __init__(self, colour='blue'):
print "I'm a Norwegian %s." % colour
def on_load(self):
print "Loaded"

--
Steven

Michael Spencer

unread,
Mar 17, 2009, 12:02:13 AM3/17/09
to pytho...@python.org
thomas...@gmail.com wrote:
...

>
> So any ideas on how to get a function called on an object just after
> __init__ is done executing?
> --
> http://mail.python.org/mailman/listinfo/python-list
>

Yes, you *can* use metaclasses - you need to override the type.__call__ method,
which is what normally calls __new__ then __init__:

>>> class MetaOnLoad(type):
... def __call__(cls, *args, **kw):
... obj=type.__call__(cls, *args, **kw)
... obj.on_load()
... return obj
...
>>> class A(object):
... __metaclass__ = MetaOnLoad
... def __init__(self):
... print "__init__ A"
... def on_load(self):
... print "on_load"
...
>>> class B(A):
... def __init__(self):
... super(B,self).__init__()
... print "__init__ B"
...
>>> b=B()
__init__ A
__init__ B
on_load
>>> class C(B):
... def __init__(self):
... super(C,self).__init__()
... print "__init__ C"
...
>>> c=C()
__init__ A
__init__ B
__init__ C
on_load
>>> #Check that __new__ machinery is still available:
>>> class D(C):
... def __new__(cls,*args, **kw):
... obj = object.__new__(cls, *args, **kw)
... print "__new__ D"
... return obj
...
>>> d=D()
__new__ D
__init__ A
__init__ B
__init__ C
on_load
>>>

HTH
Michael

0 new messages