名称为

时间:2016-06-09 17:30:38

标签: python flask decorator python-decorators

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

这就是我现在所拥有的:

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

我想做这样的事情:

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

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

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

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

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

1 个答案:

答案 0 :(得分:3)

您可以使用inspect.getargspec() function访问函数中使用的名称:

def access_course_permission(argument_name):
    def decorator(f):
        argspec = inspect.getargspec(f)
        argument_index = argspec.args.index(argument_name)
        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

上面找出你的具体论点所处的索引;这包括位置和关键字参数(因为在Python中,您也可以按位置传递关键字参数的值)。

但请注意,对于您的具体示例,Flask会使用view_course作为关键字参数来调用course_id,因此使用kwargs[argument_name]就足够了。

您必须传入字符串来命名该参数:

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