【问题标题】:Custom decorator in flask not working?烧瓶中的自定义装饰器不起作用?
【发布时间】:2013-04-19 02:24:22
【问题描述】:

我有以下代码:

import datetime
from flask.app import Flask

app = Flask(__name__)
app.config.from_object(__name__)
app.debug = True

def track_time_spent(name):
  def decorator(f):
    def wrapped(*args, **kwargs):
      start = datetime.datetime.now()
      ret = f(*args, **kwargs)
      delta = datetime.datetime.now() - start
      print name, "took", delta.total_seconds(), "seconds"
      return ret
    return wrapped
  return decorator

@app.route('/foo')
@track_time_spent('foo')
def foo():
  print "foo"
  return "foo"

@app.route('/bar')
@track_time_spent('bar')
def bar():
  print "bar"
  return "bar"

我无法让 foo 返回 'foo':

$ curl localhost:8888/foo
bar

(flask window) 
bar
bar took 8.2e-05 seconds
127.0.0.1 - - [18/Apr/2013 19:21:31] "GET /foo HTTP/1.1" 200 -

$ curl localhost:8888/bar
bar

(flask window)
bar
bar took 3.5e-05 seconds
127.0.0.1 - - [18/Apr/2013 19:21:35] "GET /bar HTTP/1.1" 200 -

发生了什么事?为什么我的装饰器不起作用?

编辑

我认为你们似乎无法看到问题所在。

当我在@track_time_spent 之前有@app.route 时,两种 方法都会返回 bar。这里的错误是调用 localhost:8888/foo 在 http 响应和打印函数中都会导致 bar

【问题讨论】:

  • “其他窗口”是什么意思?
  • flask 不使用您“直接”编写的函数对象,而是将其存储到底层 werkzeug 库中并根据请求调用它们。

标签: python flask decorator


【解决方案1】:

当您切换装饰器的顺序时,其他答案似乎缺失了“bar”作为来自“/foo”的响应。您必须在此处使用@wraps,除非您手动更新__name____module__ 等。 Flask 使用您的方法有点像单例,并且将您的装饰器视为 wrapped() 方法,而不是您实际包装的方法。因此,您的路线将不断被最后一种使用装饰器的方法覆盖。

import datetime
from functools import wraps

from flask.app import Flask

app = Flask(__name__)
app.config.from_object(__name__)
app.debug = True


def track_time_spent(name):
    def decorator(f):
        @wraps(f)
        def wrapped(*args, **kwargs):
            start = datetime.datetime.now()
            ret = f(*args, **kwargs)
            delta = datetime.datetime.now() - start
            print name, "took", delta.total_seconds(), "seconds"
            return ret
        return wrapped
    return decorator


@app.route('/foo')
@track_time_spent('foo')
def foo():
    print "foo"
    return "foo"


@app.route('/bar')
@track_time_spent('bar')
def bar():
    print "bar"
    return "bar"

app.run(host='0.0.0.0', port=8888)

【讨论】:

    【解决方案2】:

    Flask 的route 函数是一个注册函数,因为您调用它是因为它的副作用——它会为端点注册您的视图函数。但是,您只注册了视图函数,而不是 decorated 视图函数。只需切换装饰器的顺序即可注册“时间跟踪”功能。

    此外,您可以使用@app.before_request 和@app.teardown_request-registered 函数更可靠地跟踪时间(考虑渲染模板所花费的时间等)。

    【讨论】:

      【解决方案3】:

      你为什么说你的装饰器不起作用?

      在您的第二个示例中,装饰器正在运行,这样一个简单的函数将在 0.035 毫秒内执行是现实的(3.5e-05 是一种表示法,表示 3.5 乘以 10 的 -5 次方)。


      作为参考,您需要颠倒两个装饰器的顺序的原因是因为app.route 注册了它正在传递的函数。

      因此您需要将修饰函数传递给它,因此需要传递顺序。

      【讨论】:

      • 我声称我的装饰器不起作用,因为访问 /foo 返回 'bar'
      猜你喜欢
      • 2020-08-12
      • 2012-07-14
      • 2014-08-25
      • 2018-08-11
      • 1970-01-01
      • 2015-11-09
      • 2019-11-13
      • 2020-09-20
      • 2016-03-11
      相关资源
      最近更新 更多