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

Chris Mellon arkanes at gmail.com
Thu Oct 19 11:25:55 EDT 2006


On 19 Oct 2006 06:43:49 -0700, WakeBdr <bbull at optiosoftware.com> 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?


You can't do it as fully magically as I'd like, because at the time
decorators are run, the methods are just functions and aren't bound as
methods yet (so you can't automagically add methods to the class, for
example - you'd need to do that after the class definition finishes
executing). You *could* decorate all the functions you want to have
special return types, then (after the class definition) loop through
those to generate the extra return funcs.

You can do it with a minimum of boilerplate this way:

from functools import wraps #only in 2.5, you can do this by hand in 2.4
#wrapped is the function we're calling and returning as XML
#xmlfunc is the stub function we're replacing
def returnXML(wrapped):
    def f(xmlfunc):
        @wraps(xmlfunc)
        def xmlMethod(self):
            return self.asXML(wrapped(self))
        return xmlMethod
    return f

class T(object):
    def getUser(self):
        return "user"
    def asXML(self, data):
        return "<xml>%s</xml>"%(data)
    @returnXML(getUser)
    def getUserAsXML(self):pass



t = T()
print t.getUserAsXML()



More information about the Python-list mailing list