我一直在尝试创建一个可以与python中的函数和方法一起使用的装饰器。它本身并不难,但是在创建带有参数的装饰器时,似乎确实如此。
class methods(object): def __init__(self, *_methods): self.methods = _methods def __call__(self, func): def inner(request, *args, **kwargs): print request return func(request, *args, **kwargs) return inner def __get__(self, obj, type=None): if obj is None: return self new_func = self.func.__get__(obj, type) return self.__class__(new_func)
上面的代码正确地包装了函数/方法,但是对于方法,request参数是它正在操作的实例,而不是第一个非自变量。
request
有没有办法判断装饰器是应用于函数而不是方法,并进行相应处理?
扩大__get__方法。可以将其概括为装饰器装饰器。
__get__
class _MethodDecoratorAdaptor(object): def __init__(self, decorator, func): self.decorator = decorator self.func = func def __call__(self, *args, **kwargs): return self.decorator(self.func)(*args, **kwargs) def __get__(self, instance, owner): return self.decorator(self.func.__get__(instance, owner)) def auto_adapt_to_methods(decorator): """Allows you to use the same decorator on methods and functions, hiding the self argument from the decorator.""" def adapt(func): return _MethodDecoratorAdaptor(decorator, func) return adapt
这样,您可以使装饰器自动适应其使用条件。
def allowed(*allowed_methods): @auto_adapt_to_methods def wrapper(func): def wrapped(request): if request not in allowed_methods: raise ValueError("Invalid method %s" % request) return func(request) return wrapped return wrapper
请注意,包装函数在所有函数调用中都被调用,因此不要在其中做任何昂贵的事情。
装饰器的用法:
class Foo(object): @allowed('GET', 'POST') def do(self, request): print "Request %s on %s" % (request, self) @allowed('GET') def do(request): print "Plain request %s" % request Foo().do('GET') # Works Foo().do('POST') # Raises