By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
432,508 Members | 1,823 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 432,508 IT Pros & Developers. It's quick & easy.

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

P: n/a
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?

thanks

Oct 19 '06 #1
Share this Question
Share on Google+
8 Replies


P: n/a
On 19 Oct 2006 06:43:49 -0700, WakeBdr <bb***@optiosoftware.comwrote:
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()
Oct 19 '06 #2

P: n/a
WakeBdr schrieb:
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?
Use a metaclass.

class Magic(type):
def __new__(cls, name, bases, d):
for name, function in d.items():
try:
function._marked
def toXML(self, *args, **kwargs):
return self._toXML(function(self, *args, **kwargs))
def toFOO(self, *args, **kwargs):
return self._toFOO(function(self, *args, **kwargs))
d[name + "XML"] = toXML
d[name + "FOO"] = toFOO
except AttributeError:
pass
return type(name, bases, d)
def mark(f):
f._marked = True
return f

class MyClass(object):
__metaclass__ = Magic

def _toXML(self, value):
return "Look Ma, its XML! %r" % value

def _toFOO(self, value):
return "Look Ma, its FOO! %r" % value
@mark
def someMethod(self):
return "Its the data, son"
o = MyClass()

print o.someMethod()
print o.someMethodXML()
print o.someMethodFOO()

Diez
Oct 19 '06 #3

P: n/a
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
Oct 19 '06 #4

P: n/a
Diez,
What does the function._marked accomplish?

Diez B. Roggisch wrote:
WakeBdr schrieb:
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?

Use a metaclass.

class Magic(type):
def __new__(cls, name, bases, d):
for name, function in d.items():
try:
function._marked
def toXML(self, *args, **kwargs):
return self._toXML(function(self, *args, **kwargs))
def toFOO(self, *args, **kwargs):
return self._toFOO(function(self, *args, **kwargs))
d[name + "XML"] = toXML
d[name + "FOO"] = toFOO
except AttributeError:
pass
return type(name, bases, d)
def mark(f):
f._marked = True
return f

class MyClass(object):
__metaclass__ = Magic

def _toXML(self, value):
return "Look Ma, its XML! %r" % value

def _toFOO(self, value):
return "Look Ma, its FOO! %r" % value
@mark
def someMethod(self):
return "Its the data, son"
o = MyClass()

print o.someMethod()
print o.someMethodXML()
print o.someMethodFOO()

Diez
Oct 19 '06 #5

P: n/a
WakeBdr schrieb:
Diez,
What does the function._marked accomplish?
Its a decorator that tells the metaclass which functions to provide with
a *XML/*FOO variant as well. I thought that was pretty obvious, given
the name "mark" and all that.

Diez
Oct 19 '06 #6

P: n/a
Diez,
I get what that accomplishes now, but I'm having problems in my
implementation. I was able to write a standalone class that worked
correctly. However, in my code the class that I need to exhibit this
functionality inherits from another class. This seems to cause
problems when I attempt to implement you solution.

Let's say I have two classes that look like the following:

class Parent:
def getUsers(self, params):
raise 'Not implemented'

def _toXML(self, result):
return result.toXML()

def _toList(self, result):
return result.toList()

class Child(Parent):
def getUsers(self, params):
return users.query(dbc)
Caller object would say something like:
ch = Child()
ch.getUsersAsXML(params)

How would I implement your solution in this scenario. I've tried
"marking" the parent method, "marking" the child method, "marking"
both, but nothing seems to work.

WakeBdr wrote:
Diez,
What does the function._marked accomplish?

Diez B. Roggisch wrote:
WakeBdr schrieb:
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?
Use a metaclass.

class Magic(type):
def __new__(cls, name, bases, d):
for name, function in d.items():
try:
function._marked
def toXML(self, *args, **kwargs):
return self._toXML(function(self, *args, **kwargs))
def toFOO(self, *args, **kwargs):
return self._toFOO(function(self, *args, **kwargs))
d[name + "XML"] = toXML
d[name + "FOO"] = toFOO
except AttributeError:
pass
return type(name, bases, d)
def mark(f):
f._marked = True
return f

class MyClass(object):
__metaclass__ = Magic

def _toXML(self, value):
return "Look Ma, its XML! %r" % value

def _toFOO(self, value):
return "Look Ma, its FOO! %r" % value
@mark
def someMethod(self):
return "Its the data, son"
o = MyClass()

print o.someMethod()
print o.someMethodXML()
print o.someMethodFOO()

Diez
Oct 20 '06 #7

P: n/a
WakeBdr schrieb:
Diez,
I get what that accomplishes now, but I'm having problems in my
implementation. I was able to write a standalone class that worked
correctly. However, in my code the class that I need to exhibit this
functionality inherits from another class. This seems to cause
problems when I attempt to implement you solution.
You need to give a __metaclass__ to one of them, and I think they must
be new-style-classes.
Diez
Oct 20 '06 #8

P: n/a
OK, I think I'm close now. I just can't get past this one error. Here
is my code, followed by the output produced when I run it.

class Magic(type):
def __new__(cls, name, bases, d):
for name, function in d.items():
try:
function._marked
print 'Class: %s' % cls
print 'Method: %s' % name
def toXML(self, *args, **kwargs):
return
self._toXML(function(self, *args, **kwargs))
def toList(self, *args, **kwargs):
return
self._toList(function(self, *args, **kwargs))
d[name+'XML'] = toXML
d[name+'List'] = toList
except AttributeError:
#traceback.print_exc()
pass
return type(name, bases, d)

def mark(f):
f._marked = True
return f

class test(object):

def _toXML(self, value):
return '<xml>%s</xml>' % value
def _toList(self, value):
return '<list>%s</list>' % value

class testtest(test):

__metaclass__ = Magic

@mark
def printData(self, data):
return 'child-%s' % data
t = testtest()
print t.printData('data')
print t.printDataXML('data')
print t.printDataList('data')

===========OUTPUT=========
Class: <class '__main__.Magic'>
Method: printData
child-data
Traceback (most recent call last):
File "test.py", line 43, in ?
print t.printDataXML('data')
File "test.py", line 11, in toXML
return self._toXML(function(self, *args, **kwargs))
TypeError: __new__() takes exactly 4 arguments (3 given)

Diez B. Roggisch wrote:
WakeBdr schrieb:
Diez,
I get what that accomplishes now, but I'm having problems in my
implementation. I was able to write a standalone class that worked
correctly. However, in my code the class that I need to exhibit this
functionality inherits from another class. This seems to cause
problems when I attempt to implement you solution.

You need to give a __metaclass__ to one of them, and I think they must
be new-style-classes.
Diez
Oct 20 '06 #9

This discussion thread is closed

Replies have been disabled for this discussion.