小编典典

将相同的装饰器(带有参数)与函数和方法一起使用

python

我一直在尝试创建一个可以与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参数是它正在操作的实例,而不是第一个非自变量。

有没有办法判断装饰器是应用于函数而不是方法,并进行相应处理?


阅读 154

收藏
2020-12-20

共1个答案

小编典典

扩大__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
2020-12-20