Python 什么时候应该使用 Flask.g?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15083967/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 13:17:21  来源:igfitidea点击:

When should Flask.g be used?

pythonflask

提问by Yaniv Aknin

I sawthat gwill move from the request context to the app context in Flask 0.10, which made me confused about the intended use of g.

g将请求上下文移动到应用程序上下文瓶0.10,这让我感到困惑的预期用途g

My understanding (for Flask 0.9) is that:

我的理解(对于 Flask 0.9)是:

  • glives in the request context, i.e., created afresh when the requests starts, and available until it ends
  • gis intended to be used as a "request blackboard", where I can put stuff relevant for the duration of the request (i.e., set a flag at the beginning of the request and handle it at the end, possibly from a before_request/after_requestpair)
  • in addition to holding request-level-state, gcan and should be used for resource management, i.e., holding database connections, etc.
  • g存在于请求上下文中,即在请求开始时重新创建,并在请求结束时可用
  • g旨在用作“请求黑板”,我可以在其中放置与请求持续时间相关的内容(即,在请求的开头设置一个标志并在最后处理它,可能来自before_request/after_request对)
  • 除了保持请求级状态外,g可以而且应该用于资源管理,即保持数据库连接等。

Which of these sentences are no longer true in Flask 0.10? Can someone point me to a resource discussing the reasonsfor the change? What should I use as a "request blackboard" in Flask 0.10 - should I create my own app/extension specific thread-local proxy and push it to the context stack before_request? What's the point of resource management at the application context, if my application lives for a long while (not like a request) and thus the resources are never freed?

以下哪些句子在 Flask 0.10 中不再正确?有人可以指出我讨论更改原因的资源吗?我应该在 Flask 0.10 中使用什么作为“请求黑板” - 我应该创建自己的应用程序/扩展特定线程本地代理并将其推送到上下文堆栈before_request吗?如果我的应用程序存在很长时间(不像请求)并且资源永远不会被释放,那么在应用程序上下文中进行资源管理有什么意义?

采纳答案by theY4Kman

Advanced Flask Patterns, as linked by Markus, explains some of the changes to gin 0.10:

高级瓶模式,如由马库斯联系,解释了一些变化到g0.10:

  • gnow lives in the application context.
  • Every request pushes a new application context, wiping the old one, so gcan still be used to set flags per-request without change to code.
  • The application context is popped afterteardown_requestis called. (Armin's presentation explains this is because things like creating DB connections are tasks which setupthe environment for the request, and should not be handled inside before_requestand after_request)
  • g现在存在于应用程序上下文中。
  • 每个请求都会推送一个新的应用程序上下文,擦除旧的应用程序上下文,因此g仍可用于为每个请求设置标志,而无需更改代码。
  • 应用程序上下文teardown_request被调用弹出。(阿明的介绍解释说,这是因为事情像创建数据库连接的任务,其设置为请求的环境,而不应内部处理before_requestafter_request

回答by Jaza

As an addendum to the information in this thread: I've been a bit confused by the behavior of flask.gtoo, but some quick testing has helped me to clarify it. Here's what I tried out:

作为此线程中信息的附录:我对flask.gtoo的行为有点困惑,但一些快速测试帮助我澄清了它。这是我尝试过的:

from flask import Flask, g
app = Flask(__name__)

with app.app_context():
    print('in app context, before first request context')
    print('setting g.foo to abc')
    g.foo = 'abc'
    print('g.foo should be abc, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in first request context')
    print('g.foo should be abc, is: {0}'.format(g.foo))
    print('setting g.foo to xyz')
    g.foo = 'xyz'
    print('g.foo should be xyz, is: {0}'.format(g.foo))

print('in app context, after first request context')
print('g.foo should be abc, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in second request context')
    print('g.foo should be abc, is: {0}'.format(g.foo))
    print('setting g.foo to pqr')
    g.foo = 'pqr'
    print('g.foo should be pqr, is: {0}'.format(g.foo))

print('in app context, after second request context')
print('g.foo should be abc, is: {0}'.format(g.foo))

And here's the output that it gives:

这是它给出的输出:

in app context, before first request context
setting g.foo to abc
g.foo should be abc, is: abc  

in first request context
g.foo should be abc, is: abc
setting g.foo to xyz
g.foo should be xyz, is: xyz  

in app context, after first request context
g.foo should be abc, is: xyz  

in second request context
g.foo should be abc, is: xyz
setting g.foo to pqr
g.foo should be pqr, is: pqr  

in app context, after second request context
g.foo should be abc, is: pqr

As theY4Kman said above, "Every request pushes a new application context". And as the Flask docs say, the application context "will not be shared between requests". Now, what hasn't been explicitly stated (although I guess it's implied from these statements), and what my testing clearly shows, is that you should neverexplicitly create multiple request contexts nested inside one application context, because flask.g(and co) doesn't have any magic whereby it functions in the two different "levels" of context, with different states existing independently at the application and request levels.

正如Y4Kman 上面所说,“每个请求都会推送一个新的应用程序上下文”。而随着烧瓶文档说,应用程序上下文“将不被请求之间共享”。现在,没有明确说明的(尽管我猜这些陈述暗示了这一点),并且我的测试清楚地表明,您永远不应该显式地创建嵌套在一个应用程序上下文中的多个请求上下文,因为flask.g(和共同)没有没有任何神奇之处,它可以在两个不同的上下文“级别”中运行,不同的状态独立存在于应用程序和请求级别。

The reality is that "application context" is potentially quite a misleading name, because app.app_context()isa per-request context, exactly the same as the "request context". Think of it as a "request context lite", only required in the case where you need some of the variables that normally require a request context, but you don't need access to any request object (e.g. when running batch DB operations in a shell script). If you try and extend the application context to encompass more than one request context, you're asking for trouble. So, rather than my test above, you should instead write code like this with Flask's contexts:

现实情况是,“应用程序上下文”可能是一个相当误导的名字,因为app.app_context()一个每个请求的情况下,完全一样的“请求上下文”。将其视为“请求上下文精简版”,仅在您需要一些通常需要请求上下文的变量的情况下才需要,但您不需要访问任何请求对象(例如,在运行批处理数据库操作时外壳脚本)。如果您尝试扩展应用程序上下文以包含多个请求上下文,那么您就是在自找麻烦。因此,您应该使用 Flask 的上下文编写这样的代码,而不是我上面的测试:

from flask import Flask, g
app = Flask(__name__)

with app.app_context():
    print('in app context, before first request context')
    print('setting g.foo to abc')
    g.foo = 'abc'
    print('g.foo should be abc, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in first request context')
    print('g.foo should be None, is: {0}'.format(g.get('foo')))
    print('setting g.foo to xyz')
    g.foo = 'xyz'
    print('g.foo should be xyz, is: {0}'.format(g.foo))

with app.test_request_context():
    print('in second request context')
    print('g.foo should be None, is: {0}'.format(g.get('foo')))
    print('setting g.foo to pqr')
    g.foo = 'pqr'
    print('g.foo should be pqr, is: {0}'.format(g.foo))

Which will give the expected results:

这将给出预期的结果:

in app context, before first request context
setting g.foo to abc
g.foo should be abc, is: abc  

in first request context
g.foo should be None, is: None
setting g.foo to xyz
g.foo should be xyz, is: xyz  

in second request context
g.foo should be None, is: None
setting g.foo to pqr
g.foo should be pqr, is: pqr