Python装饰器按名称访问参数

标签 python flask decorator python-decorators

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

这是我现在拥有的:

@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 始终是第一个参数,它就可以很好地工作。然而,事实并非如此。这就是为什么我希望能够指定名称。

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

最佳答案

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

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

上面的代码找出了你的特定参数位于哪个索引;这涵盖了位置参数和关键字参数(因为在 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

但是请注意,在 Flask 中您可以访问 request.view_args ,无需从函数参数中解析此信息:

course_id = requests.view_args[argument_name]

关于Python装饰器按名称访问参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37732639/

相关文章:

python - 装饰器链接如何工作?

python - 为什么通过 python 创建表失败,但在 cli 上创建表成功?

python - R foreach 使用 rpy2 python 永远运行 jupyter 笔记本

curl - 在curl请求中将嵌套字典作为数据发送

ruby-on-rails - Ruby on Rails 模式 - 装饰者与演示者

python - 如何在默认 Django 身份验证登录 View 中使用自定义装饰器

python - 如何打印 Python 列表中的每第 4 个项目?

python - 如何使用两个单独的数据框在 Pandas 中执行 SumProduct()

flask - 如何在 Flask 应用程序中设置 static_url_path

python - 使用 Flask 显示 stackOverflow API JSON 数据