Is this a good use of __metaclass__?

Joel.Hedlund at gmail.com Joel.Hedlund at gmail.com
Sat May 6 13:36:14 EDT 2006


I played around with my old code before I saw your post, and I believe
I've found a solution that's a bit neater than what I had before. I
thought I could just as well post it if you're interested and have the
time. This one uses multiple inheritance, but it's legal and there's
only one metaclass.

When executed, this prints:
Validating admin.
Scary stuff done.

Cheers!
/Joel

Here ya go!
--------------------------------------------------------------------------
from decorator import decorator

# Metaclass for decorating public methods:
class DecoratePublicMethods(type):
    """Equip public methods of a class with a specified decorator.

    Class data members:
    decorator_attribute = '_public_method_decorator': <str>
        If this attribute of the class exists and evaluates to True,
then
        it is used to decorate all public methods of the class.
    no_decoration_attribute = '_do_not_decorate': <str>
        If this attribute of the class exists it should contain a list
of
        names of public methods that should not be decorated.

    """

    decorator_attribute = '_public_method_decorator'
    no_decoration_attribute = '_do_not_decorate'

    def __new__(cls, classname, bases, classdict):
        decorator = classdict.get(cls.decorator_attribute, None)
        if not decorator:
            return type.__new__(cls,classname,bases,classdict)
        do_not_decorate = classdict.get(cls.no_decoration_attribute,
[])
        for attr,item in classdict.items():
            if not callable(item):
                continue
            if attr in do_not_decorate or attr.startswith('_'):
                continue
            classdict[attr] = decorator(item)
        return type.__new__(cls, classname, bases, classdict)

# Some decorators:
@decorator
def validate_job(func, self, id, response, *pargs, **kwargs):
    """Bogus authentiction routine"""
    print "Validating job."
    return func(self, id, response, *pargs, **kwargs)

@decorator
def validate_user(func, self, id, response, *pargs, **kwargs):
    """Bogus authentiction routine"""
    print "Validating user."
    return func(self, id, response, *pargs, **kwargs)

@decorator
def validate_admin(func, self, id, response, *pargs, **kwargs):
    """Bogus authentiction routine"""
    print "Validating admin."
    return func(self, id, response, *pargs, **kwargs)

# My API:
class BaseAPI(object):
    __metaclass__ = DecoratePublicMethods

class JobValidatedAPI(BaseAPI):
    _public_method_decorator = validate_job
    def do_routine_stuff(self, clientid, response, foo):
        print "Routine stuff done."

class UserValidatedAPI(BaseAPI):
    _public_method_decorator = validate_user
    def do_mundane_stuff(self, clientid, response, moo):
        print "Mundane stuff done."

class AdminValidatedAPI(BaseAPI):
    _public_method_decorator = validate_admin
    def do_scary_stuff(self, clientid, response, moose):
        print "Scary stuff done."

## FIXED: Multiple inheritance now legal.
class FullAPI(JobValidatedAPI, UserValidatedAPI, AdminValidatedAPI):
    _public_method_decorator = None

# Now this works:
b = FullAPI()
b.do_scary_stuff('bofh', 2, 3)
--------------------------------------------------------------------------




More information about the Python-list mailing list