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