在烧瓶应用中保持全局状态

时间:2013-10-09 16:13:07

标签: python flask global state

我正在尝试在我的flask应用程序中保存缓存字典。

据我了解,Application Context,尤其是flask.g object应该用于此。

设定:

import flask as f

app = f.Flask(__name__)

现在,如果我这样做:

with app.app_context():
    f.g.foo = "bar"
    print f.g.foo

打印bar

继续以下内容:

with app.app_context():
    print f.g.foo

AttributeError: '_AppCtxGlobals' object has no attribute 'foo'

我不明白,而且文档根本​​没有帮助。如果我正确地阅读它们,状态应该保留下来。

我的另一个想法就是简单地使用模块范围的变量:

cache = {}

def some_function():
    cache['foo'] = "bar"

但似乎每次请求都会重置这些内容。

如何正确地做到这一点?

编辑:Flask 10.1

3 个答案:

答案 0 :(得分:57)

根据您的问题,我认为您对" global"的定义感到困惑。

在Flask设置库中,您有一个Flask服务器,其中包含多个线程,并且可能有多个进程处理请求。假设您有一个库存全局变量,例如" itemlist = []",并且您希望在每个请求中继续添加它 - 例如,每当有人向端点发出POST请求时。这在理论和实践中是完全可能的。这也是一个非常糟糕的主意。

问题在于,您无法轻松控制哪些线程和进程“赢得”#34; - 列表可能会以非常糟糕的顺序出现,或者完全被破坏。所以现在你需要谈论锁,互斥和其他原语。这很难,很烦人。

您应该将网络服务器本身保持为尽可能无状态。每个请求应该是完全独立的,不能在服务器中共享任何状态。相反,使用将为您处理状态的数据库或缓存层。这似乎更复杂,但实际上更简单。以SQLite为例;它非常简单。

要解决这个问题。'对象,即基于每个请求上的全局对象

http://flask.pocoo.org/docs/api/#flask.g

它"擦干净"在请求之间,不能用于在它们之间共享状态。

答案 1 :(得分:8)

这一行

with app.app_context():
    f.g.foo = "bar"

由于您使用的是“with”关键字,因此一旦执行此循环,它就会调用AppContext类的__exit__方法。见this。所以'foo'一旦完成就会弹出。这就是为什么你没有再次使用它。你可以尝试:

ctx = app.app_context()
f.g.foo = 'bar'
ctx.push()

在您拨打以下电话之前,g.foo应该可用

ctx.pop()

我不知道你是否想要将其用于缓存目的。

答案 2 :(得分:7)

我做了类似于你的“模块范围变量”的想法,我在烧瓶服务器中使用它,我用它来集成两个软件,我知道我将只有一个同时“用户”(作为发件人软件)。

我的app.py看起来像这样:

from flask import Flask
from flask.json import jsonify
app = Flask(__name__)

cache = {}

@app.route("/create")
def create():
    cache['foo'] = 0
    return jsonify(cache['foo'])

@app.route("/increment")
def increment():
    cache['foo'] = cache['foo'] + 1
    return jsonify(cache['foo'])

@app.route("/read")
def read():
    return jsonify(cache['foo'])

if __name__ == '__main__':
    app.run()

你可以这样测试:

import requests

print(requests.get('http://127.0.0.1:5000/create').json())
print(requests.get('http://127.0.0.1:5000/increment').json())
print(requests.get('http://127.0.0.1:5000/increment').json())
print(requests.get('http://127.0.0.1:5000/read').json())
print(requests.get('http://127.0.0.1:5000/increment').json())
print(requests.get('http://127.0.0.1:5000/create').json())
print(requests.get('http://127.0.0.1:5000/read').json())

输出:

0
1
2
2
3
0
0

谨慎使用,因为我预计这种情况在适当的多用户Web服务器环境中不起作用。