Question about accessing class-attributes.
Michele Simionato
mis6 at pitt.edu
Fri Apr 25 08:13:31 EDT 2003
"Bjorn Pettersen" <BPettersen at NAREX.com> wrote in message news:<mailman.1051212998.14005.python-list at python.org>...
> <snip>
> we get:
>
> Traceback (most recent call last):
> File "M:\python\cpoint.py", line 36, in ?
> class CountedPoint(Counted, Point):
> File "M:\python\cpoint.py", line 6, in new
> return type. new (cls, name, bases, dict)
> TypeError: metatype conflict among bases
>not exactly clear what the conflict is
The meta-type conflict is rather annoying, indeed. According to the
metaclass book, the language should generate the correct metaclass
that solves the conflict automatically, without burden for the
programmer. Python is not that magic (yet) therefore you have to
solve the conflict yourself.
I use the following solution:
def _generatemetaclass(bases,metas):
"Internal function called by child"
if metas==(type,): # trivial metaclass
metabases=(); metaname="_"
else: # non-trivial metaclass
metabases=metas
metaname="_"+''.join([m.__name__ for m in metas])
trivial=lambda m: m in metabases or m is type
for b in bases:
meta_b=type(b)
if not trivial(meta_b):
metabases+=(meta_b,)
metaname+=meta_b.__name__
if not metabases: # trivial metabase
return type
elif len(metabases)==1: # single metabase
return metabases[0]
else: # multiple metabases
return type(metaname,metabases,{}) # creates a new metaclass
#shifting the possible conflict to meta-metaclasses
def child(*bases,**options):
"""Class factory avoiding metatype conflicts: if the base classes have
metaclasses conflicting within themselves or with the given metaclass,
it automatically generates a compatible metaclass and instantiate the
child class from it. The recognized keywords in the option dictionary
are name, dic and meta."""
name=options.get('name',''.join([b.__name__ for b in bases])+'_')
dic=options.get('dic',{})
metas=options.get('metas',(type,))
return _generatemetaclass(bases,metas)(name,bases,dic)
Here there is an example of usage:
>>> class M_A(type): pass
>>> class M_B(type): pass
>>> A=M_A('A',(),{})
>>> B=M_B('B',(),{})
M_A is A's metaclass, M_B is B's metaclass. I cannot do
>>> class C(A,B): pass #error
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: metatype conflict among base
but I can do
>>> C=child(A,B,name='C')
>>> C
<class 'oopp.C'>
>>> type(C) # automatically generated metaclass
<class 'oopp._M_AM_B'>
HTH,,
Michele
More information about the Python-list
mailing list