creating classes with mix-ins

Carl Banks pavlovevidence at gmail.com
Mon May 11 22:01:13 EDT 2009


On May 11, 11:16 am, samwyse <samw... at gmail.com> wrote:
> I'm writing a class that derives it's functionality from mix-ins.
> Here's the code:
>
>     def boilerplate(what):   # This used to be a decorator, but all of
> the
>         ##what = f.__name__  # function bodies turned out to be
> 'pass'.
>         'Validate the user, then call the appropriate plug-in.'
>         def template(self, which, username, password, *args):
>             if not self.security.isAuthorised(username, password,
> which, what):
>                 raise Exception('Unauthorised access')
>             return getattr(self.blog, what)(which, *args)
>         template.__name__ = what
>         template.__doc__ = getattr(self.blog, what).__doc__
>         return template
>
>     class MetaWeblog(object):
>         def __init__(self,
>                      securityHandler=SimpleSecurityHandler,
>                      blogHandler=SimpleBlogHandler):
>             self.security = securityHandler()
>             self.blog = blogHandler()
>         newPost = boilerplate('newPost')
>         editPost = boilerplate('editPost')
>         getPost = boilerplate('getPost')
>         # etc, etc, etc
>
> I'd like to replace the method definitions with a loop:
>         for what in attr_list:
>             setattr(klass, what, boilerplate(what))
>
> That begs the question of where I define 'klass' and 'attr_list'.
> Should I use a class decorator, or a metaclass?

Here's the thing: unless you have advance knowledge of the methods
defined by self.blog, you can't get the attr_list at class definition
time, which means neither the metaclass nor the decorator would be a
good approach.  If that's the case, you should define newPost,
editPost, and whatever other methods of self.blog as ordinary
attributes of self, within the init function.  boilerplate would be
the same except you would pass self to it and allow template to use it
from its nested scope (it would no longer be an instance method since
it's an ordinary attribute).

If you do know what the methods of self.blog will be, then that's
where you get attr_list from.  So, for instance, if blogHandler always
returns an object of type Blog, then you could inspect Blog's type
dict to see what methods are defined in it; in fact you probably want
to check the whole MRO for Blog, like this (untested):

attr_list = []
for cls in Blog.__mro__:
    for value in cls.__dict__:
        if is_wrapped_method(value):
            attr_list.append(value)


A metaclass is probably overkill to assign the wrapped blog methods.
I probably wouldn't even bother with the decorator, and just write the
loop after the class definition.  Then you can use MetaBlog directly
for klass.

class MetaBlog(object):
    ...

for what in attr_list:
    setattr(MetaBlog, what, boilerplate(what))


If it were the kind of thing I found myself doing often I'd refactor
into a decorator.


Carl Banks



More information about the Python-list mailing list