another question on metaclasses

0 views
Skip to first unread message

Michele Simionato

unread,
Dec 10, 2002, 2:01:17 PM12/10/02
to
I am trying to understand metaclasses and this is my first program
using them. I post it in order to have some feedback, since I don't feel
completely confident with the subject yet. I would like to know if what I
am doing is correct and if there are better ways to accomplish the same.

Here is the motivation for the script. It is very common to have a class
B with some __init__ method which is extended in a derived class C:

class B(object):
def __init__(self,*args,**kw):
print "This is B.__init__"

class C(B):
def __init__(self,*args,**kw):
B.__init__(self,*args,**kw)
print "This is C.__init__"

Notice that the B.__init__ method has to be called explicitly. In general
this is fine, but in some cases it would be handy to have B.__init__ called
automatically. To perform this, I used metaclasses:

-------------- begin MetaInit.py -----------------------

class MetaInit(type):
"""If cls inherits from bases, and cls.__metaclass__==MetaInit, then
cls.__init__ is extended to call super(cls).__init__ ."""
def __init__(cls,name,bases,dict):
child_init=cls.__init__ #makes a copy ?
def double_init(self,*args,**kw):
"Both the super and the child __init__ are called"
super(cls,self).__init__(self,*args,**kw)
child_init(self,*args,**kw)
setattr(cls,'__init__',double_init)

class Autoinit(object):
"""Autoinit should be thought as a mixin class. Classes derived from
Autoinit automagically call their super __init__ methods according to
the MRO. The magic works because Autoinit-derived classes inherit the
Autoinit metaclass MetaInit. Notice that Autounit itself inherit its
__init__ method from object, which does nothing."""
__metaclass__ = MetaInit

class B(Autoinit):
def __init__(self,*args,**kw):
print "This is B.__init__"

class C(Autoinit):
def __init__(self,*args,**kw):
print "This is C.__init__"

class D(B,C):
def __init__(self,*args,**kw):
print "This is D.__init__"

d=D()

------- end MetaInit.py -------

The output of this program is

This is C.__init__
This is B.__init__
This is D.__init__

i.e. what I want. Nevertheless, I wonder if there are cases where this script
could break down, then I ask the Python gurus for comments and feedback.
TIA,


--
Michele Simionato - Dept. of Physics and Astronomy
210 Allen Hall Pittsburgh PA 15260 U.S.A.
Phone: 001-412-624-9041 Fax: 001-412-624-9163
Home-page: http://www.phyast.pitt.edu/~micheles/

Lulu of the Lotus-Eaters

unread,
Dec 10, 2002, 2:27:19 PM12/10/02
to
mi...@pitt.edu (Michele Simionato) wrote previously:

|to understand metaclasses and this is my first program using them.
|Here is the motivation for the script. It is very common to have a class
|B with some __init__ method which is extended in a derived class C:

I think this example is cool enough that I saved it. But I still have
to wonder about this, much as I do about most metaclass examples,
whether one really -needs- metaclasses to do this. Of even if there is
anything clearer, easier to maintain, or any other advantage, about this
style.

Unfortunately, most of the posts discussing metaclasses still seem to be
at the level of "I'm trying to think of something to do with
metaclasses" (I've posted some like this too, I don't mean it as a
criticism).

The way I would generally approach this issue is with something like:

>>> class Super:
... def __init__(self):
... print "...in Super"
... self.init()
...
>>> class Child(Super):
... def init(self):
... print "...in Child"
...
>>> c = Child()
...in Super
...in Child

You could make this better, of course: maybe check for the '.init()'
method before calling it; or raise NotImplementedError specifically;
pass along some arguments to '.init()'; look through
'self.__class__.__bases__' for methods to call; and other stuff. Is
there anything that the metaclass approach gets you that a variant on
this one does not?

Yours, Lulu...


--
mertz@ | The specter of free information is haunting the `Net! All the
gnosis | powers of IP- and crypto-tyranny have entered into an unholy
.cx | alliance...ideas have nothing to lose but their chains. Unite
| against "intellectual property" and anti-privacy regimes!
-------------------------------------------------------------------------


Michele Simionato

unread,
Dec 10, 2002, 5:55:42 PM12/10/02
to
Lulu wrote:

> But I still have to wonder about this, much as I do about most metaclass
> examples, whether one really -needs- metaclasses to do this. Of even if
> there is anything clearer, easier to maintain, or any other advantage, about
> this style.

I thought exactly this for some time, this is the reason why I never took
in consideration the metaclasses approach until now. I was quite skeptical
about its advantages. But now I am reading "Putting Metaclasses to Work" and
I have got the feeling that there is something more in metaclasses.
The magic is somewhat in the fact that metaclasses can be inherited and used
in mixins as in the simple example I wrote. But still I haven't found a very
compelling example for the use of metaclasses, nor I fully grasp the
concept and its implications (yet). Nevertheless, my attitude is changing.
Until yesterday I was very skeptical about Alex Martelli's claims on the
power of metaclasses, today I have the impression that there is some meat in
and not only the smoke. But still I haven't seen a compelling example
in comp.lang.python (at least, one that I could understand ;-)


Michele

Mike Dean

unread,
Dec 10, 2002, 8:31:52 PM12/10/02
to
On 10 Dec 2002 14:55:42 -0800 Michele Simionato <mi...@pitt.edu> wrote:
> But still I haven't seen a compelling example in comp.lang.python (at
> least, one that I could understand ;-)

Disclaimer: I, too, haven't been able to use metaclasses practically
myself - mainly just played with how they work, and was amazed at their
versatility (and the things you can do _without_ them).

But, I can envision one immensly practical application -
object-relational mappers. Say you have a metaclass, DBSerializable.
This metaclass takes the classes attributes, which are supposed to hold
sentinel objects representing data types, and generates a class with all
the database serialization code automatically. So you can do:

class Client:
__metaclass__ = DBSerializable

id = DB_Int
name = DB_Str(50)
sales_rep_id = DB_Int(link=SalesRep.id)

and the metaclass wrapps everything in properties that automatically
handle database stuff, making everything smooth and transparent. Also,
maybe another metaclass makes the object model network-transparent, etc.

Hmm, I wonder if something like MiddleKit will ever adopt such an
idea...

-Mike

Greg Chapman

unread,
Dec 11, 2002, 8:36:03 AM12/11/02
to
On 10 Dec 2002 11:01:17 -0800, mi...@pitt.edu (Michele Simionato) wrote:

>i.e. what I want. Nevertheless, I wonder if there are cases where this script
>could break down, then I ask the Python gurus for comments and feedback.

It may break if any of the Autoinit classes do not have an __init__ method:

class B(Autoinit):
def __init__(self,*args,**kw):
print "This is B.__init__"

class C(B):
pass

class D(C):


def __init__(self,*args,**kw):
print "This is D.__init__"

d=D()

prints:

This is B.__init__
This is B.__init__
This is D.__init__

This is because cls.__init__ will return the nearest base class's __init__ if
cls does not itself define __init__. Your meta __init__ should probably look
like:

def __init__(cls,name,bases,dict):
child_init=cls.__dict__.get('__init__')


def double_init(self,*args,**kw):
"Both the super and the child __init__ are called"
super(cls,self).__init__(self,*args,**kw)

if child_init:
child_init(self,*args,**kw)
setattr(cls,'__init__',double_init)

---
Greg Chapman

Reply all
Reply to author
Forward
0 new messages