I have a class that has an output() method which returns a matplotlib Figure instance. I have a decorator I wrote that takes that fig instance and turns it into a Django response object.
My decorator looks like this:
class plot_svg(object):
def __init__(self, view):
self.view = view
def __call__(self, *args, **kwargs):
print args, kwargs
fig = self.view(*args, **kwargs)
canvas=FigureCanvas(fig)
response=HttpResponse(content_type='image/svg+xml')
canvas.print_svg(response)
return response
and this is how it was being used:
def as_avg(self):
return plot_svg(self.output)()
The only reason I has it that way instead of using the "@" syntax is because when I do it with the "@":
@plot_svg
def as_svg(self):
return self.output()
I get this error:
as_svg() takes exactly 1 argument (0 given)
I'm trying to 'fix' this by putting it in the "@" syntax but I can't figure out how to get it working. I'm thinking it has something to do with self not getting passed where it's supposed to...
Right: when you decorate with a class, instead of with a function, you have to make it a descriptor (give it a __get__ method, at least) to get the "automatic self". Simplest is to decorate with a function instead:
def plot_svg(view):
def wrapper(*args, **kwargs):
print args, kwargs
fig = view(*args, **kwargs)
canvas = FigureCanvas(fig)
response = HttpResponse(content_type='image/svg+xml')
canvas.print_svg(response)
return response
return wrapper
Background: the reason functions "become methods" (when defined in a class and accessed on an instance thereof by attribute-get notation), in other words, the reason such functions can get their automatic self is that they're descriptors -- the function type has a __get__.
A class doesn't have a __get__ method -- unless you explicitly add one. So why not just decorate with a function instead, as in the above example? This way you get the nice __get__ of functions automatically -- and as you see the nested function "lexical closure" property doesn't pose any problem at all (indeed, it simplifies things -- the nested function calls view, not self.view which might be rather confusing if self could mean either an instance of your decorator class OR an instance of the class whose method you're decorating...!-).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With