上下文局部

您可能会发现,您在每个请求期间都有一些数据,您希望跨函数使用这些数据。您可能希望将它们作为全局数据进行访问,而不是将它们作为参数在每个函数之间传递。然而,在PythonWeb应用程序中使用全局变量并不是线程安全的;不同的工作进程可能会干扰彼此的数据。

在请求过程中,您必须使用上下文局部变量,而不是使用全局变量来存储公共数据。上下文本地是全局定义/导入的,但它包含的数据特定于当前线程、异步任务或greenlet。您不会意外地获取或覆盖其他工作人员的数据。

在Python中存储每个上下文的数据的当前方法是 contextvars 模块。上下文变量按线程、异步任务或greenlet存储数据。这将取代较旧的 threading.local 它只处理线程。

Werkzeug提供了包装纸 ContextVar 以使其更容易使用。

代理对象

LocalProxy 允许直接将上下文变量视为对象,而不需要使用和检查 ContextVar.get() 。如果设置了上下文变量,则本地代理的外观和行为将与该变量设置为的对象相似。如果未设置,则会引发 RuntimeError 在大多数操作中都会出现异常。

from contextvars import ContextVar
from werkzeug.local import LocalProxy

_request_var = ContextVar("request")
request = LocalProxy(_request_var)

from werkzeug.wrappers import Request

@Request.application
def app(r):
    _request_var.set(r)
    check_auth()
    ...

from werkzeug.exceptions import Unauthorized

def check_auth():
    if request.form["username"] != "admin":
        raise Unauthorized()

访问 request 将指向每个服务器工作者正在处理的特定请求。你可以治疗 request 就像一个真正的 Request 对象。

bool(proxy) 永远都会回来 False 如果未设置var,则。如果需要直接访问对象而不是代理,可以使用 _get_current_object() 方法。

class werkzeug.local.LocalProxy(local, name=None, *, unbound_message=None)

绑定到上下文本地对象的对象的代理。代理上的所有操作都被转发到绑定对象。如果没有绑定任何对象,则会引发 RuntimeError 都被养大了。

参数:
  • local -- 提供代理对象的上下文本地对象。

  • name -- 代理对象中的该属性。

  • unbound_message -- 显示上下文本地对象是否解除绑定的错误消息。

代理服务器A ContextVar 以使其更容易访问。传递一个名称以代理该属性。

_request_var = ContextVar("request")
request = LocalProxy(_request_var)
session = LocalProxy(_request_var, "session")

代理上的属性 Local 命名空间,方法是使用以下属性名称调用本地:

data = Local()
user = data("user")

代理上的顶端项 LocalStack 打电话给当地人。传递一个名称以代理该属性。

app_stack = LocalStack()
current_app = app_stack()
g = app_stack("g")

传递一个函数以代理该函数的返回值。在被直接支持之前,它以前用于访问本地对象的属性。

session = LocalProxy(lambda: request.session)

__repr____class__ 都是代理的,所以 repr(x)isinstance(x, cls) 将看起来像代理对象。使用 issubclass(type(x), LocalProxy) 要检查对象是否为代理,请执行以下操作。

repr(user)  # <User admin>
isinstance(user, User)  # True
issubclass(type(user), LocalProxy)  # True
Changelog

在 2.2.2 版本发生变更: __wrapped__ 在包装对象时设置,而不仅仅是在包装函数时设置,以防止doctest失败。

在 2.2 版本发生变更: 可以代理 ContextVarLocalStack 直接去吧。

在 2.2 版本发生变更: 这个 name 参数可以与任何代理对象一起使用,不仅 Local

在 2.2 版本发生变更: 添加了 unbound_message 参数。

在 2.0 版本发生变更: 更新了代理属性和方法以反映当前数据模型。

在 0.6.1 版本发生变更: 类可以使用Callable实例化。

_get_current_object: Callable[[], T]

返回此代理绑定到的当前对象。如果代理未绑定,则会引发 RuntimeError

如果需要将对象传递给不理解代理的对象,则应使用此选项。如果您在一个函数中多次访问对象,而不是多次通过代理,则它对于提高性能也很有用。

堆栈和命名空间

ContextVar 一次存储一个值。您可能会发现需要存储一堆项或具有多个属性的命名空间。可以使用列表或字典来处理这些内容,但将它们用作上下文变量值需要格外小心。Werkzeug提供 LocalStack 它包装了一个列表,并且 Local 这就说明了一个问题。

存在与这些对象相关的一定程度的性能损失。因为列表和词典是可变的, LocalStackLocal 需要做额外的工作以确保数据不会在嵌套的上下文之间共享。如果可能,将您的应用程序设计为使用 LocalProxy 直接围绕上下文变量。

class werkzeug.local.LocalStack(context_var=None)

创建一个上下文本地数据堆栈。这包装了一个 ContextVar 包含一个 list 价值。

与使用单个上下文变量相比,这可能会导致性能损失,因为它必须复制数据以避免在嵌套上下文之间更改列表。

参数:

context_var (ContextVar[list[T]] | None) -- 这个 ContextVar 用作此本地数据库的存储。如果没有给出,将创建一个。不是在全局范围内创建的上下文变量可能会干扰垃圾收集。

Changelog

在 2.0 版本发生变更: 用途 ContextVar 而不是定制存储实现。

在 0.6.1 版本加入.

__call__(name=None, *, unbound_message=None)

创建 LocalProxy 访问此本地堆栈顶部的。

参数:
  • name (str | None) -- 如果给定,代理将访问顶层项的此属性,而不是项本身。

  • unbound_message (str | None) -- 如果堆栈为空,代理将显示的错误消息。

返回类型:

LocalProxy

pop()

从堆栈中移除顶部的项并将其返回。如果堆栈为空,则返回 None

返回类型:

T | None

push(obj)

将新项添加到堆栈顶部。

参数:

obj (T) --

返回类型:

list[~T]

property top: T | None

堆栈上最顶层的项。如果堆栈为空, None 返回。

class werkzeug.local.Local(context_var=None)

创建上下文本地数据的命名空间。这包装了一个 ContextVar 包含一个 dict 价值。

与使用单个上下文变量相比,这可能会导致性能损失,因为它必须复制数据以避免在嵌套上下文之间改变字典。

参数:

context_var (ContextVar[dict[str, t.Any]] | None) -- 这个 ContextVar 用作此本地数据库的存储。如果没有给出,将创建一个。不是在全局范围内创建的上下文变量可能会干扰垃圾收集。

Changelog

在 2.0 版本发生变更: 用途 ContextVar 而不是定制存储实现。

__call__(name, *, unbound_message=None)

创建 LocalProxy 访问此本地命名空间上的属性的。

参数:
  • name (str) -- 代理该属性。

  • unbound_message (str | None) -- 如果未设置该属性,代理将显示的错误消息。

返回类型:

LocalProxy

发布数据

以前的实现 Local 使用的内部数据结构无法在每个上下文结束时自动清除。相反,可以使用以下实用程序来发布数据。

警告

现代实现应该不需要这样做,因为上下文变量中的数据是由Python自动管理的。它暂时被保留是为了兼容,但将来可能会被移除。

class werkzeug.local.LocalManager(locals=None)

管理在一个或多个环境中发布当前上下文的数据 LocalLocalStack 物体。

现代用例不需要这样做,将来可能会删除。

参数:

locals (None | (Local | LocalStack | t.Iterable[Local | LocalStack])) -- 要管理的本地人员或本地人员列表。

Changelog

在 2.1 版本发生变更: 这个 ident_func 被移除了。

在 0.7 版本发生变更: 这个 ident_func 参数已添加。

在 0.6.1 版本发生变更: 这个 release_local() 函数可以用来代替管理器。

cleanup()

释放此上下文的本地变量中的数据。在每次请求或使用结束时调用此方法 make_middleware()

返回类型:

None

make_middleware(app)

包装WSGI应用程序,以便在发送请求响应后自动释放本地数据。

参数:

app (WSGIApplication) --

返回类型:

WSGIApplication

middleware(func)

喜欢 make_middleware() 但用作WSGI应用程序函数的装饰符。

@manager.middleware
def application(environ, start_response):
    ...
参数:

func (WSGIApplication) --

返回类型:

WSGIApplication

werkzeug.local.release_local(local)

中释放当前上下文的数据。 LocalLocalStack 而不使用 LocalManager

现代用例不需要这样做,将来可能会删除。

Changelog

在 0.6.1 版本加入.

参数:

local (Local | LocalStack) --

返回类型:

None