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