Python 中的上下文变量 [英] Context variables in Python

查看:98
本文介绍了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(或查找您的框架已经定义的一个)和 getset 值,如上所示,然后你应该没问题.

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 的使用可能会在后台进行,作为各种库的实现细节,这些库希望拥有一个不会在线程之间或线程之间泄漏更改的全局"状态在单个线程中分离异步任务.在这种情况下,上面的示例可能更有意义:f1f3 是同一个库的一部分,而 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆