假设我的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
我的问题是:
修改
由于多种原因(架构遗产,图书馆等)我无法改变f2
等中间函数的签名,因此我可以&# 39; t只是将user_id
作为参数传递,不会将所有这些函数放在同一个类中。
答案 0 :(得分:4)
您可以在Python 3.7中使用subview
来了解您的问题。这通常很容易:
override func viewDidLoad() {
super.viewDidLoad()
for view in setView.subviews {
mySubViews.append(view)
let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(getIndex(_:)))
gestureRecognizer.delegate = self
view.addGestureRecognizer(gestureRecognizer)
}
}
@objc func getIndex(_ sender:UIView) {
print(mySubViews.index(of: sender))
}
contextvars
上的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
方法返回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)
(或查找已由您的框架定义过的),并在其上显示contextvars
和ContextVar
值,如上所示,您应该很高兴。
许多get
的使用可能会在后台,作为各种图书馆的实施细节,希望拥有一个全球的"不会在线程之间或单个线程内的单独异步任务之间泄漏更改的状态。在这种情况下,上面的示例可能更有意义:set
和contextvars
是同一个库的一部分,而f1
是用户提供的回调,传递到其他地方的库中。
答案 1 :(得分:3)
基本上你正在寻找的是一种在一组功能之间共享状态的方法。在面向对象语言中这样做的规范方法是使用类:
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()
使用此解决方案,您的类实例(此处为f
)是"上下文"其中执行函数 - 每个实例都有自己的专用上下文。
功能编程的等价物是使用闭包,我不打算在这里给出一个例子,因为虽然Python支持闭包,但它仍然是第一个,主要是对象语言所以OO解决方案是最多的明显。
最后,干净的程序解决方案是在调用链中传递此上下文(可以表示为dict
或任何类似的数据类型),如DFE的答案中所示。
作为一般规则:依靠全局变量或某些"魔法"可以 - 或者不是 - 由你设置的上下文 - 不管是谁也不是在哪里 - 也不是 - 什么时候使代码变得困难,如果不是不可能的推理,那可以以最不可预测的方式打破(谷歌搜索&# 34;全球邪恶"将会产生关于这个主题的大量文章。)
答案 2 :(得分:1)
您可以在函数调用中使用kwargs以传递
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, user_id=user_id)
def f2(operation, **kwargs):
# do something, not important, and then call another function
f3(operation, **kwargs)
def f3(operation, **kwargs):
# get user_id if there is a variable user_id in the context, get `None` otherwise
user_id = kwargs.get("user_id")
# do something with user_id and operation
kwargs
dict等同于您在上下文变量中看到的内容,但仅限于调用堆栈。它是在每个函数中传递(通过指针式)的相同内存元素,而不是在内存中复制变量。
在我看来,但我想看看你们都在想什么,上下文变量是一种优雅的方式来授权全局变量并控制它。