Python上下文管理器,用于还原变量';s值多少?
如何编写上下文管理器将变量恢复为其原始值?例如:Python上下文管理器,用于还原变量';s值多少?,python,with-statement,contextmanager,Python,With Statement,Contextmanager,如何编写上下文管理器将变量恢复为其原始值?例如: x = 5 with Restorer(x): x = 6 ... print(x) 产出将是: 5这仅在特定情况下才可能实现。通常,上下文管理器只获取x的值(实际上是一个引用)。它无法访问变量本身 对于全局变量,如果调用函数定义在同一个模块中(或者代码只是放在同一个模块中,没有周围的函数),则调用可以编写为 with Restorer('x'): 然后,恢复程序可以是(省略错误检查): 利用contextlib.contextm
x = 5
with Restorer(x):
x = 6
...
print(x)
产出将是:
5这仅在特定情况下才可能实现。通常,上下文管理器只获取
x
的值(实际上是一个引用)。它无法访问变量本身
对于全局变量,如果调用函数定义在同一个模块中(或者代码只是放在同一个模块中,没有周围的函数),则调用可以编写为
with Restorer('x'):
然后,恢复程序可以是(省略错误检查):
利用
contextlib.contextmanager
,您可以在yield
语句之后将x
重新指定为其原始值:
import contextlib
x = 5
@contextlib.contextmanager
def Restorer(val):
yield
global x
x = val
print(x)
with Restorer(x):
x = 6
print('in contextmanager:', x)
print('outside contextmanager', x)
输出:
5
in contextmanager: 6
outside contextmanager 5
5
5
您可以滥用
class
语句来引入临时“作用域”:
这“起作用”是因为Foo
没有建立真正的新作用域,这意味着第一个print(x)
指的是当前作用域中的名称x
,但临时无人区中的赋值准备创建同名的类属性,该属性用于主体的其余部分。然而,我相信,这足以模拟你的要求
(也就是说,实际上不要使用它。如果需要某种临时覆盖,请编写适当的函数,或手动保存值。)这更多地与名称的范围有关,而不是与变量有关 您可以通过创建具有块行为的函数来创建作用域:
def behaviour():
x = 6
...
x = 5
behaviour()
print(x)
输出:
5
in contextmanager: 6
outside contextmanager 5
5
5
或者,您可以引入一个新名称:
x = 5
y = 6
...
print(x)
输出:
5
in contextmanager: 6
outside contextmanager 5
5
5
@PeterWood在这种特殊情况下,使用Restorer('x'):这样的调用可能会起作用。@PeterWood好的,不。是的,这是正确的。我看了@PeterWood的帖子并尝试了这个,是的,它适用于globals。我很想知道我们是否能更一般化?我假设在一些晦涩难懂的python模块中没有隐藏的“变量引用”可以使用?除了源代码,没有。python只是缺少提供所需内容的特殊作用域类型。我认为
val
作为参数是多余的。只需做globalx;val=x;产量x=val
这将需要为要还原的每个变量定义一个新的定义,并且只使用全局名称,而不是当前范围内的任何名称。@PeterWood您可以将其替换为global x;old_val=x;产量x=old_val
,但这并不是真的好或坏,只是不同而已。(我看你在编辑评论后也想到了同样的事情。)@PeterWood这是真的,但是,我创建了参数val
,以对应OP的示例。这对于可变类型来说更容易,例如list
。为什么需要这样做?这是一种方便的模式,可以避免潜在的错误。您可以在块中使用不同的名称,或者提取到函数中。python调用堆栈在堆栈框架中为您管理本地名称的上下文。只需通过调用函数创建一个新的作用域。