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调用堆栈在堆栈框架中为您管理本地名称的上下文。只需通过调用函数创建一个新的作用域。