Jun*_*ius 5 python python-3.x python-3.7
假设我的Python应用程序中有一个定义某种上下文的函数- user_id例如。此函数调用不将此上下文作为函数参数的其他函数。例如:
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
Run Code Online (Sandbox Code Playgroud)
我的问题是:
编辑
由于多种原因(架构遗留,库等),我无法/不会更改诸如的中间函数的签名f2,因此我不能仅user_id作为参数传递,也不能将所有这些函数放在同一个类中。
您可以contextvars在Python 3.7中使用所要查询的内容。通常很简单:
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
Run Code Online (Sandbox Code Playgroud)
上的set方法ContextVar返回一个Token实例,您可以使用该实例将变量重置为set操作发生之前的值。因此,如果您想f1以某种方式还原事物(对user_id上下文变量不是很有用,但是与诸如在decimal模块中设置精度之类的事物更相关),则可以执行以下操作:
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)
Run Code Online (Sandbox Code Playgroud)
该contextvars模块除了提供更多功能外,但您几乎肯定不需要处理其他内容。如果您是从头开始编写自己的异步框架,则可能仅需要创建自己的上下文并在其他上下文中运行代码。
如果您只是在使用现有框架(或编写您想与异步代码完美兼容的库),则无需处理这些东西。只需创建一个全局变量ContextVar(或查找一个已经由您的框架定义的全局变量)并对其get进行set赋值,如上所示,那么您就应该做好了。
各种contextvars用途的实现细节可能会在后台使用,这是各种库的实现细节,这些库希望具有“全局”状态,而不会泄漏线程之间或单个线程中单独的异步任务之间的更改。上面的示例在这种情况下可能更有意义:f1并且f3属于同一库,并且f2是由用户提供的回调传递到其他地方的库中。
本质上,您正在寻找的是一种在一组函数之间共享状态的方法。在面向对象语言中这样做的规范方法是使用类:
class Foo(object):
def __init__(self, operation, user=None):
self._operation = operation
self._user_id = user.id if user else None
def f1(self):
print("in f1 : {}".format(self._user_id))
self.f2()
def f2(self):
print("in f2 : {}".format(self._user_id))
self.f3()
def f3(self):
print("in f3 : {}".format(self._user_id))
f = Foo(operation, user)
f.f1()
Run Code Online (Sandbox Code Playgroud)
使用此解决方案,您的类实例(此处f)是执行函数的“上下文”——每个实例都有自己的专用上下文。
等价的函数式编程是使用闭包,我不打算在这里举例,因为虽然 Python 支持闭包,但它仍然是第一个并且主要是对象语言,因此 OO 解决方案是最明显的。
最后,干净的程序解决方案是在dict整个调用链中传递这个上下文(可以表示为 a或任何类似的数据类型),如 DFE 的回答所示。
作为一般规则:依赖全局变量或一些“魔法”上下文,这些上下文可能 - 或不 - 由 you-dont-who-nor-where-nor-when 设置,从而生成难以推理的代码,这可能会以最不可预测的方式打破(谷歌搜索“全球邪恶”会产生大量关于该主题的文献)。
| 归档时间: |
|
| 查看次数: |
4757 次 |
| 最近记录: |