I have this decorator, used to decorate a django view when I do not want the view to be executed if the share
argument is True
(handled by middleware)
class no_share(object):
def __init__(self, view):
self.view = view
def __call__(self, request, *args, **kwargs):
"""Don't let them in if it's shared"""
if kwargs.get('shared', True):
from django.http import Http404
raise Http404('not availiable for sharing')
return self.view(request, *args, **kwargs)
It currently works like this:
@no_share
def prefs(request, [...])
But I'm wanting to expand the functionality a little bit, so that it will work like this:
@no_share('prefs')
def prefs(request, [...])
My question is how can I modify this decorator class so that it accepts extra arguments?
The decorator arguments are accessible to the inner decorator through a closure, exactly like how the wrapped() inner function can access f . And since closures extend to all the levels of inner functions, arg is also accessible from within wrapped() if necessary.
When to Use a Decorator in Python. You'll use a decorator when you need to change the behavior of a function without modifying the function itself. A few good examples are when you want to add logging, test performance, perform caching, verify permissions, and so on.
Decorators use a special syntax in JavaScript, whereby they are prefixed with an @ symbol and placed immediately before the code being decorated.
I hope this article by Bruce Eckel helps.
Upd: According to the article your code will look like this:
class no_share(object):
def __init__(self, arg1):
self.arg1 = arg1
def __call__(self, f):
"""Don't let them in if it's shared"""
# Do something with the argument passed to the decorator.
print 'Decorator arguments:', self.arg1
def wrapped_f(request, *args, **kwargs):
if kwargs.get('shared', True):
from django.http import Http404
raise Http404('not availiable for sharing')
f(request, *args, **kwargs)
return wrapped_f
to be used as desired:
@no_share('prefs')
def prefs(request, [...])
The Bruce Eckel article that Li0liQ mentioned should be helpful in figuring this out. Decorators with and with out arguments behave slightly differently. The big difference is that when you pass arguments the __call__ method gets called once on __init__ and it is supposed to return a function that will be called whenever the decorated function is called. When there are no arguments, the __call__ method gets called every time the decorated function is called.
What does this mean for you? The way that __init__ and __call__ are called for a @no_arg_decorator
is different than they are called for a @decorator('with','args')
.
Here are two decorators that might do the trick for you. You can get away with just the @no_share_on(...) decorator as long as you always use it with the parentheses.
def sharing_check(view, attr_name, request, *args, **kwargs):
if kwargs.get(attr_name, True):
from django.http import Http404
raise Http404('not availiable for sharing')
return view(request, *args, **kwargs)
class no_share(object):
"""A decorator w/o arguments. Usage:
@no_share
def f(request):
...
"""
def __init__(self, view):
self.view = view
def __call__(self, request, *args, **kwargs):
return sharing_check(self.view, 'sharing', request, *args, **kwargs)
class no_share_on(object):
"""A decorator w/ arguments. Usage:
@no_share_on('something')
def f(request):
...
--OR--
@no_share_on()
def g(request):
...
"""
def __init__(self, attr_name='sharing'):
self.attr_name = attr_name
def __call__(self, view):
def wrapper_f(request, *args, **kwargs):
return sharing_check(view, self.attr_name, request, *args, **kwargs)
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