Can I use decorators to manipulate return type or create methods?

Peter Otten __peter__ at web.de
Thu Oct 19 18:52:40 CEST 2006


WakeBdr wrote:

> I'm writing a class that will query a database for some data and return
> the result to the caller.  I need to be able to return the result of
> the query in several different ways: list, xml, dictionary, etc.  I was
> wondering if I can use decorators to accomplish this.
> 
> For instance, I have the following method
> 
> def getUsers(self, params):
>     return users.query(dbc)
> 
> To get the appropriate return types, I also have these methods.  I have
> these convenience methods for every query method in my class.
> 
> def getUsersAsXML(self, params):
>     return self._toXML(self.getUsers(params))
> def getUsersAsDict(self, params):
>     return self._toDict(self.getUsers(params))
> def getUsersAsList(self, params):
>     return self._toList(self.getUsers(params))
> 
> Instead of creating these three methods for every query method, is
> there a way to use decorators to manipulate the return type.  I'd still
> like to have the caller use getUsersAsXML, I just don't want to write
> the AsXML methods for every query method.  So the decorator would
> essentially create the convenience methods instead of me coding them.
> 
> One solution that I don't want to use is passing a variable into the
> query method that determines the return type.  This is what I don't
> want to do.
> def getUsers(self, params, returnType):
> 
> Any ideas on how I can accomplish this?

Here's an odd approach, entirely based on naming conventions:

from operator import attrgetter

class Composer(object):
    def __getattr__(self, name):
        prefix, delim, suffix = name.rpartition("_as_")
        if prefix and suffix:
            cls = self.__class__
            inner = attrgetter(prefix)
            outer = attrgetter(delim + suffix)
            def wrapped(self, *args):
                return outer(self)(inner(self)(*args))
            setattr(cls, name, wrapped)
            return getattr(self, name)
        raise AttributeError("sorry, no %r" % name)

class A(Composer):
    def _as_xml(self, obj):
        return "as_xml(%s)" % (obj,)
    def _as_list(self, obj):
        return "as_list(%s)" % (obj,)
    def get_users(self):
        return "get_users()"

class B(A):
    def _as_list(self, obj):
        return "AS_LIST(%s)" % (obj,)
    def get_artist_as_a_young_man(self, name):
        return "get_artist_as_a_young_man(name=%r)" % name

if __name__ == "__main__":
    a = A()
    b = B()
    print a.get_users_as_list()
    print b.get_users_as_list()
    print a.get_users_as_xml()
    print b.get_artist_as_a_young_man_as_xml("James")
    print a.get_artist_as_a_young_man_as_xml("James") # AttributeError

Peter



More information about the Python-list mailing list