上下文局部变量 — Werkzeug 文档

来自菜鸟教程
Werkzeug/docs/2.0.x/local
跳转至:导航、​搜索

上下文局部变量

迟早你会在每个视图或辅助函数或其他任何东西中拥有一些东西。 在 PHP 中,要走的路是全局变量。 然而,这在 WSGI 应用程序中是不可能的,除非有一个主要缺点:一旦您在全局命名空间上操作,您的应用程序就不再是线程安全的。

Python 标准库有一个称为“线程局部变量”(或线程局部数据)的概念。 线程局部是一个全局对象,您可以在其中放入东西,然后以线程安全和特定于线程的方式返回。 这意味着无论何时您在线程本地对象上设置或获取值,线程本地对象都会检查您所在的线程并检索与您的线程对应的值(如果存在)。 因此,您不会意外获得另一个线程的数据。

然而,这种方法有一些缺点。 例如,除了线程,Python 中还有其他类型的并发。 一个非常受欢迎的是greenlets。 此外,WSGI 不保证每个请求是否都有自己的线程。 可能是请求正在重用先前请求中的线程,因此数据留在线程本地对象中。

Werkzeug 提供了自己的本地数据存储实现,称为 werkzeug.local。 这种方法为线程局部变量提供了类似的功能,但也适用于 greenlets。

这是一个如何使用 werkzeug.local 的简单示例:

from werkzeug.local import Local, LocalManager

local = Local()
local_manager = LocalManager([local])

def application(environ, start_response):
    local.request = request = Request(environ)
    ...

application = local_manager.make_middleware(application)

这将请求绑定到 local.request。 在同一上下文中在此赋值之后执行的所有其他代码都可以安全地访问 local.request 并获得相同的请求对象。 本地管理器上的 make_middleware 方法确保在请求后清除对本地对象的所有引用。

相同的上下文意味着同一线程和同一进程中的相同 greenlet(如果您使用的是 greenlet)。

如果本地对象上尚未设置请求对象,而您尝试访问它,您将收到 AttributeError。 您可以使用 getattr 来避免这种情况:

def get_request():
    return getattr(local, 'request', None)

如果请求不可用(还?),这将尝试获取请求或返回 None。

请注意,本地对象无法自行管理,因此您需要一个本地管理器。 您可以将多个本地人传递给本地管理器,或者稍后通过将它们附加到 manager.locals 来添加其他内容,并且每次管理器清理时,它都会清除此上下文中保留在本地人中的所有数据。