Is this a good use of __metaclass__?

Bruno Desthuilliers bdesth.quelquechose at free.quelquepart.fr
Fri May 5 19:21:05 EDT 2006


Joel Hedlund a écrit :
> Hi!
> 
> I need some input on my use of metaclasses since I'm not sure I'm using 
> them in a pythonic and graceful manner. I'm very grateful for any tips, 
> pointers and RTFMs I can get from you guys.
> 
> Below, you'll find some background info and an executable code example.
> 
> In the code example I have two ways of doing the same thing. The problem 
> is that the "Neat" version doesn't work, and the "Ugly" version that 
> works gives me the creeps.
> 
> The "Neat" version raises a TypeError when I try the multiple 
> inheritance (marked with comment in the code):
> 
> Traceback (most recent call last):
>   File "/bioinfo/yohell/pybox/gridjs/gridjs-2.0/test.py", line 132, in ?
>     class FullAPI(JobAPI, UserAPI, AdminAPI):
>   File "/bioinfo/yohell/pybox/gridjs/gridjs-2.0/test.py", line 43, in 
> __new__
>     return type.__new__(cls,classname,bases,classdict)
> TypeError: Error when calling the metaclass bases
>     metaclass conflict: the metaclass of a derived class must be a 
> (non-strict) subclass of the metaclasses of all its bases

http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/204197

> In the "Ugly" version, I'm changing the metaclass in the global scope 
> between class definitions, 

Yuck.

> and that gives me bad vibes.
> 
> What should I do? Is there a way to fix my "Neat" solution? Is my "Ugly" 
> solution in fact not so horrid as I think it is? Or should I rethink the 
> whole idea? Or maybe stick with decorating manually (or in 
> BaseAPI.__init__)?

I'd go for 'manually decorating' anyway. Metaclasses can be really handy 
for framework-like stuff, but for the use case you describe, I think the 
  explicit decorator option is much more, well, explicit - and also more 
flexible - than metaclass black magic. This may also help you 
distinguish 'published' API from implementation (which is what CherryPy 
do). And finally, this may let you organize your code more freely - you 
can mix methods needing different decorators in a same class.

Also, and FWIW, you may want to favor composition-delegation (which is a 
piece of cake in Python, see below...) over inheritance. This is more 
flexible. You would then have a 'server' class that just provides common 
services and dispatch to specialized objects.

class Dispatcher(object):
   def __init__(self, delegates):
     self._delegates = delegates

  def __getattr__(self, name):
    for delegate in self._delegates:
      try:
        return getattr(delegate, name):
      except AttributeError:
        pass
   else:
     err = "object '%s' has no attribute '%s'" \
           % (self.__class__.__name__, name)
     raise AttributeError(err)

# note that you may want to reorganize your code differently
# if you go for explicit decorators
d = Dispatcher(JobApi, UserApi, AdminApi)


My 2 cents...



More information about the Python-list mailing list