对函数和方法使用相同的装饰器(带参数) [英] Using the same decorator (with arguments) with functions and methods

查看:23
本文介绍了对函数和方法使用相同的装饰器(带参数)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试创建一个装饰器,它可以与 Python 中的函数和方法一起使用.这本身并不难,但是当创建一个带参数的装饰器时,它似乎是.

I have been trying to create a decorator that can be used with both functions and methods in python. This on it's own is not that hard, but when creating a decorator that takes arguments, it seems to be.

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 参数是它正在操作的实例,而不是第一个非 self 参数.

The above code wraps the function/method correctly, but in the case of a method, the request argument is the instance it is operating on, not the first non-self argument.

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

Is there a way to tell if the decorator is being applied to a function instead of a method, and deal accordingly?

推荐答案

扩展 __get__ 方法.这可以概括为一个装饰器装饰器.

To expand on the __get__ approach. This can be generalized into a decorator decorator.

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

这样你就可以让你的装饰器自动适应它使用的条件.

In this way you can just make your decorator automatically adapt to the conditions it is used in.

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

请注意,所有函数调用都会调用包装函数,所以不要在那里做任何昂贵的事情.

Notice that the wrapper function is called on all function calls, so don't do anything expensive there.

装饰器的使用:

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

这篇关于对函数和方法使用相同的装饰器(带参数)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆