Python装饰器访问参数的名称

ian*_*n93 2 python decorator flask python-decorators

我想制作一个可以接受参数(正在装饰的函数中参数的名称)并使用该参数在函数中查找参数值的Python装饰器。我知道这听起来很混乱,哈!但是我想要做的看起来像这样(它是针对Flask Web应用程序):

这就是我现在所拥有的:

@app.route('/admin/courses/<int:course_id>')
def view_course(course_id):
    ... view code here
Run Code Online (Sandbox Code Playgroud)

我想做这样的事情:

@app.route('/admin/courses/<int:course_id>')
@access_course_permission(course_id)
def view_course(course_id):
    ... view code here
Run Code Online (Sandbox Code Playgroud)

现在,我知道我可以做类似的事情:

def access_course_permission(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        # check args[0] right here to find the course ID
        return f(*args, **kwargs)
    return decorated_function
Run Code Online (Sandbox Code Playgroud)

只要course_id始终是第一个参数,它就可以很好地工作。但是,事实并非如此。这就是为什么我希望能够指定名称。

如果这不可能,我想我可以将参数的索引传递给装饰器,但这不是很好。

Mar*_*ers 5

您可以使用该inspect.getfullargspec()函数来访问函数中使用的名称:

try:
    # Python 3
    from inspect import getfullargspec
except ImportError:
    # Python 2, use inspect.getargspec instead
    # this is the same function really, without support for annotations
    # and keyword-only arguments
    from inspect import getargspec as getfullargspec

from functools import wraps

def access_course_permission(argument_name):
    def decorator(f):
        argspec = getfullargspec(f)
        argument_index = argspec.args.index(argument_name)
        @wraps(f)
        def wrapper(*args, **kwargs):
            try:
                value = args[argument_index]
            except IndexError:
                value = kwargs[argument_name]
            # do something with value
            return f(*args, **kwargs)
        return wrapper
    return decorator
Run Code Online (Sandbox Code Playgroud)

上面的代码可以找到您的特定参数位于哪个索引处;这涵盖了位置参数和关键字参数(因为在Python中,您也可以按位置为关键字参数传递值)。

但是请注意,您的具体的例子,瓶将调用view_coursecourse_id一个关键字参数,所以使用kwargs[argument_name]就足够了。

您必须传递一个字符串来命名该参数:

@app.route('/admin/courses/<int:course_id>')
@access_course_permission('course_id')
def view_course(course_id):
    # ... view code here
Run Code Online (Sandbox Code Playgroud)