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