Python 中的上下文变量 [英] Context variables in Python
问题描述
假设我的 Python 应用程序中有一个函数定义了某种上下文 - 例如一个 user_id
.此函数调用其他不将此上下文作为函数参数的函数.例如:
Suppose that I have a function in my Python application that define some kind of context - a user_id
for example. This function call other functions that do not take this context as a function argument. For example:
def f1(user, operation):
user_id = user.id
# somehow define user_id as a global/context variable for any function call inside this scope
f2(operation)
def f2(operation):
# do something, not important, and then call another function
f3(operation)
def f3(operation):
# get user_id if there is a variable user_id in the context, get `None` otherwise
user_id = getcontext("user_id")
# do something with user_id and operation
我的问题是:
- Python 3.7 的上下文变量能否用于此目的?怎么样?
- 这是这些上下文变量的用途吗?
- 如何使用 Python v3.6 或更早版本执行此操作?
- Can the Context Variables of Python 3.7 be used for this? How?
- Is this what these Context Variables are intended for?
- How to do this with Python v3.6 or earlier?
编辑
出于多种原因(架构遗留、库等)我不能/不会改变像 f2
这样的中间函数的签名,所以我不能只需将 user_id
作为参数传递,不要将所有这些函数放在同一个类中.
For multiple reasons (architectural legacy, libraries, etc) I can't/won't change the signature of intermediary functions like f2
, so I can't just pass user_id
as arguments, neither place all those functions inside the same class.
推荐答案
您可以在 Python 3.7 中使用 contextvars
来解决您的问题.这通常很容易:
You can use contextvars
in Python 3.7 for what you're asking about. It's usually really easy:
import contextvars
user_id = contextvars.ContextVar("user_id")
def f1(user, operation):
user_id.set(user.id)
f2()
def f2():
f3()
def f3():
print(user_id.get(default=None)) # gets the user_id value, or None if no value is set
ContextVar
上的 set
方法返回一个 Token
实例,您可以使用该实例将变量重置为它之前的值set
操作发生.因此,如果您希望 f1
以它们的方式恢复事物(对于 user_id
上下文变量不是很有用,但与在 中设置精度之类的东西更相关十进制
模块),你可以这样做:
The set
method on the ContextVar
returns a Token
instance, which you can use to reset the variable to the value it had before the set
operation took place. So if you wanted f1
to restore things the way they were (not really useful for a user_id
context variable, but more relevant for something like setting the precision in the decimal
module), you can do:
token = some_context_var.set(value)
try:
do_stuff() # can use value from some_context_var with some_context_var.get()
finally:
some_context_var.reset(token)
contextvars
模块不止于此,但您几乎肯定不需要处理其他内容.如果您从头开始编写自己的异步框架,您可能只需要创建自己的上下文并在其他上下文中运行代码.
There's more to the contextvars
module than this, but you almost certainly don't need to deal with the other stuff. You probably only need to be creating your own contexts and running code in other contexts if you're writing your own asynchronous framework from scratch.
如果您只是使用一个现有的框架(或编写一个您想很好地处理异步代码的库),那么您不需要处理这些东西.只需创建一个全局 ContextVar
(或查找您的框架已经定义的一个)和 get
和 set
值,如上所示,然后你应该没问题.
If you're just using an existing framework (or writing a library that you want to play nice with asynchronous code), you don't need to deal with that stuff. Just create a global ContextVar
(or look up one already defined by your framework) and get
and set
values on it as shown above, and you should be good to go.
许多 contextvars
的使用可能会在后台进行,作为各种库的实现细节,这些库希望拥有一个不会在线程之间或线程之间泄漏更改的全局"状态在单个线程中分离异步任务.在这种情况下,上面的示例可能更有意义:f1
和 f3
是同一个库的一部分,而 f2
是用户-提供的回调传递到其他地方的库中.
A lot of contextvars
use is probably going to be in the background, as an implementation detail of various libraries that want to have a "global" state that doesn't leak changes between threads or between separate asynchronous tasks within a single thread. The example above might make more sense in this kind of situation: f1
and f3
are part of the same library, and f2
is a user-supplied callback passed into the library somewhere else.
这篇关于Python 中的上下文变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!