【问题标题】:Python decorator with Flask带有 Flask 的 Python 装饰器
【发布时间】:2014-02-16 15:07:50
【问题描述】:

我需要在 Flask 路由函数中添加一个 python 装饰器,(基本上我从here 编辑了代码)

def requires_admin(f):
    def wrapper(f):
        @wraps(f)
        def wrapped(*args, **kwargs):
            #if not admin:
                #return render_template('error.html')
            return f(*args, **kwargs)
        return wrapped
    return wrapper

并像这样使用它就可以了:

@app.route('/admin/action')
@requires_admin
def AdminAction():
#NO error if NO parameter

但是这样使用会报错:

@app.route('/admin/action/<int:id>')
@requires_admin
def AdminAction(id):

在 Flask 0.10 中,我得到这样的错误(我刚刚从 Flask 0.9 更新到 0.10,而在 Flask 0.9 中没有这样的语法错误):

    @requires_admin
  File "/usr/local/lib/python2.6/dist-packages/Flask-0.10.1-py2.6.egg/flask/app.
py", line 1013, in decorator
    self.add_url_rule(rule, endpoint, f, **options)
  File "/usr/local/lib/python2.6/dist-packages/Flask-0.10.1-py2.6.egg/flask/app.
py", line 62, in wrapper_func
    return f(self, *args, **kwargs)
  File "/usr/local/lib/python2.6/dist-packages/Flask-0.10.1-py2.6.egg/flask/app.
py", line 984, in add_url_rule
    'existing endpoint function: %s' % endpoint)
AssertionError: View function mapping is overwriting an existing endpoint functi
on: wrapper

我对装饰器的东西很陌生,我该如何纠正这个错误?

【问题讨论】:

  • 不是 100% 确定,但您可能需要为路由提供 endpoint 参数?见stackoverflow.com/questions/17540754/…
  • @will-hart 我刚刚更新了这个问题。只有带参数才会出错。
  • @JamesKing 这是stackoverflow.com/questions/28381560/… 一个很好的问题。你只是因为缺乏努力而投了反对票。回来尝试,我会准备提供答案。
  • @Avinash Raj 感谢您的关注。我自己解决了这个问题。我的问题实际上是如何使用 Python 内联编辑文件。答案是import fileinput

标签: python flask decorator


【解决方案1】:

你有两个包装函数,你只需要一个。请注意,每个包装函数都有一个参数。这应该是正在发生的事情的线索。

你有:

def decorator(take_a_function):
    def wrapper1(take_a_function):
        def wrapper2(*takes_multiple_arguments):
           # do stuff
           return take_a_function(*takes_multiple_arguments)

        return wrapper2
    return wrapper1

当你用它装饰一个函数时:

@decorator
def my_function(*takes_multiple_arguments):
   pass

这相当于:

def my_function(*takes_multiple_arguments):
   pass

my_function = decorator(my_function)

但是执行decorator(my_function) 会返回wrapper1,如果你记得需要一个 论点,take_a_function。这显然不是你想要的。您希望返回 wrapper2。如您的回答,解决方案是删除外包装(wrapper1):

from functools import wraps

def decorator(takes_a_function):
    @wraps(takes_a_function)
    def wrapper(*args, **kwargs):
        # logic here
        return takes_a_function(*args, **kwargs)

    return wrapper

【讨论】:

    【解决方案2】:

    好的,我通过阅读@will-hart 给出的答案Route to view_func with same decorators "flask" 解决了这个问题

    我只是删除了def wrapper(f),现在一切似乎都很好。至少没有语法错误。

    from functools import wraps
    
    def requires_admin(f):
        @wraps(f)
        def wrapped(*args, **kwargs):
            #if blah blah:
                #return blah blah
            return f(*args, **kwargs)
        return wrapped
    

    因为我对装饰师很陌生,我不知道为什么。但希望这可以帮助其他人。

    【讨论】:

    • 一般来说,除了包装函数之外没有参数的装饰器只需要一个内部函数。在您的第一个示例中,requires_admin 返回一个函数,该函数又采用第二个函数。两级装饰器用于@app.route(extra_args)@wraps(f)
    猜你喜欢
    • 2020-01-15
    • 2020-07-15
    • 2014-07-21
    • 2013-09-21
    • 2011-05-28
    • 1970-01-01
    • 2014-10-04
    • 2018-02-27
    • 2020-07-24
    相关资源
    最近更新 更多