Q: Meta-class usage

D

daishi

Hi,

I am wondering if someone could help me understand some of the
details of using metaclasses.

I am trying to use metaclasses to auto-generate some attributes
and methods in a class definition. I am attaching a simplified
example of the kind of code I am considering below, and I have
the following questions:

1. Is the code in NamedType.__new__ the "right" way to have a
class which has NamedType as its metaclass inherit from
NamedClass? Are the semantics different from if the class with
NamedType as its metaclass explicitly listed NamedClass as a
superclass in the standard way?
2. Is the try/except clause in NameType.__init__ the "right"
way to prevent KeyErrors for subclasses of classes with
NamedType as its metaclass?

Thanks in advance,
d

---
class NamedClass(object):
def __init__(self, name):
self.name = name

class NamedType(type):
def __new__(mcl, name, bases, dictionary):
bases = tuple(list(bases)+[NamedClass])
return super(NamedType, mcl).__new__(mcl, name, bases, dictionary)
def __init__(cls, name, bases, dictionary):
try:
name = dictionary['NAME']
except KeyError:
return
def is_a(self):
return self.name == name
setattr(cls, 'is_a_'+name, is_a)
def init(self):
super(cls, self).__init__(name)
setattr(cls, '__init__', init)

class PrintNamedType(NamedType):
def __init__(cls, name, bases, dictionary):
super(PrintNamedType, cls).__init__(name, bases, dictionary)
def print_name(self):
print self.name
setattr(cls, 'print_name', print_name)

class NamedFoo:
__metaclass__ = NamedType
NAME = 'foo'

class SubNamedFoo(NamedFoo):
pass

class NamedBar:
__metaclass__ = PrintNamedType
NAME = 'bar'
 
M

Michael Hudson

Hi,

I am wondering if someone could help me understand some of the
details of using metaclasses.

I am trying to use metaclasses to auto-generate some attributes
and methods in a class definition. I am attaching a simplified
example of the kind of code I am considering below, and I have
the following questions:

1. Is the code in NamedType.__new__ the "right" way to have a
class which has NamedType as its metaclass inherit from
NamedClass?

Apart from the fact that tuple(list(bases)+[NamedClass]) is a strange
way of spelling bases + (NamedClass,), yes.
Are the semantics different from if the class with NamedType as its
metaclass explicitly listed NamedClass as a superclass in the
standard way?

Well, potentially, depending on where in the bases list you put
NamedClass. In general, it might be wise to not add NamedClass to the
bases list unless you need to (to avoid MRO calculation errors).
2. Is the try/except clause in NameType.__init__ the "right" way to
prevent KeyErrors for subclasses of classes with NamedType as its
metaclass?

I'd say so, but I'm not totally sure what you're trying to achieve...

Cheers,
mwh
 
D

daishi

Hi Michael,

Thanks for the response. Some followup inline.

Michael Hudson said:
Hi,

I am wondering if someone could help me understand some of the
details of using metaclasses.

I am trying to use metaclasses to auto-generate some attributes
and methods in a class definition. I am attaching a simplified
example of the kind of code I am considering below, and I have
the following questions:

1. Is the code in NamedType.__new__ the "right" way to have a
class which has NamedType as its metaclass inherit from
NamedClass?

Apart from the fact that tuple(list(bases)+[NamedClass]) is a strange
way of spelling bases + (NamedClass,), yes.

Thanks; I had forgotten about being able to do that w/ tuples.
Well, potentially, depending on where in the bases list you put
NamedClass. In general, it might be wise to not add NamedClass to the
bases list unless you need to (to avoid MRO calculation errors).

I was/am having some difficulties understanding what happens here.
E.g., in the example code that I gave if I make the class definition
of NamedFoo to have an explicit superclass:

class NamedFoo(object):

I obtain the error:

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "meta2.py", line 28, in ?
class NamedFoo(object):
File "meta2.py", line 8, in __new__
return super(NamedType, mcl).__new__(mcl, name, bases, dictionary)
TypeError: Cannot create a consistent method resolution
order (MRO) for bases object, NamedClass

If I add NamedClass to the beginning by doing:

bases = (NamedClass,) + bases

(instead of appending to the end of bases),

I obtain the error:

Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "meta2.py", line 32, in ?
class SubNamedFoo(NamedFoo):
File "meta2.py", line 8, in __new__
return super(NamedType, mcl).__new__(mcl, name, bases, dictionary)
TypeError: Cannot create a consistent method resolution
order (MRO) for bases NamedFoo, NamedClass

(Note that the error is now for class SubNamedFoo instead of
NamedFoo.)

Now based on http://www.python.org/2.3/mro.html I believe this has to
do with the fact that in the first case of NamedFoo we have
merge([object], [NamedClass, object], [object, NamedClass])
(as opposed to
merge([NamedClass, object], [object], [NamedClass, object])
when the modification to bases is changed)

And the SubNamedFoo error arises because of
merge([NamedClass, object], [NamedFoo, NamedClass, object],
[NamedClass, NamedFoo, object])

Is this correct?
(I just want to make sure that I am understanding what's going on
correctly.)
I'd say so, but I'm not totally sure what you're trying to achieve...

The basic idea of what I'm trying to do is (I think) fairly simple.
I have several fairly similar class definitions that I want, and I
was hoping to use metaclasses to make their definition more compact.
(As comparison, I would use a #define in C or a defmacro in Lisp).
I would like to use these classes once defined as if they were
regularly defined classes, included subclassing. My initial attempt
at subclassing with subclass class SubNamedFoo(NamedFoo) failed
because of the fact that since the metaclass of SubNamedFoo inherits
from NamedFoo and hence becomes NamedType, and the NamedType.__init__
is executed for SubNamedFoo also, which I didn't want - I would like
SubNamedFoo to be oblivious of the fact that NamedFoo was defined
using a customized metaclass. I was wondering what the ideal way to
achieve this might be.
Cheers,
mwh

Thanks again,
d
 
M

Michele Simionato

Now based on http://www.python.org/2.3/mro.html I believe this has to
do with the fact that in the first case of NamedFoo we have
merge([object], [NamedClass, object], [object, NamedClass])
(as opposed to
merge([NamedClass, object], [object], [NamedClass, object])
when the modification to bases is changed)

And the SubNamedFoo error arises because of
merge([NamedClass, object], [NamedFoo, NamedClass, object],
[NamedClass, NamedFoo, object])

Is this correct?
(I just want to make sure that I am understanding what's going on
correctly.)

Correct. More specific classes should go first to avoid confusion
about the precedence order.
The basic idea of what I'm trying to do is (I think) fairly simple.
I have several fairly similar class definitions that I want, and I
was hoping to use metaclasses to make their definition more compact.
(As comparison, I would use a #define in C or a defmacro in Lisp).
I would like to use these classes once defined as if they were
regularly defined classes, included subclassing. My initial attempt
at subclassing with subclass class SubNamedFoo(NamedFoo) failed
because of the fact that since the metaclass of SubNamedFoo inherits
from NamedFoo and hence becomes NamedType, and the NamedType.__init__
is executed for SubNamedFoo also, which I didn't want - I would like
SubNamedFoo to be oblivious of the fact that NamedFoo was defined
using a customized metaclass. I was wondering what the ideal way to
achieve this might be.

Maybe a simple function acting as a class factory? Sometimes the
simplest solutions are the best solutions. So, unless you anticipate
the need to use inheritance of metaclasses, why don't you use a simple
function return a class (created with type(name,bases,dic), the basic
metaclass) ?

Michele
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,586
Members
45,097
Latest member
RayE496148

Latest Threads

Top