Python 上下文管理器恢复变量的值?
Python Context Manager to restore a variable's value?
您将如何编写上下文管理器来将变量恢复为其原始值?例如:
x = 5
with Restorer(x):
x = 6
...
print(x)
输出将是:
5
这只有在特定情况下才有可能。通常上下文管理器只获取x
的值(实际上是引用)。它无法访问变量本身。
对于全局变量,如果调用函数定义在同一个模块中(或者代码只是放在同一个模块中,没有周围的函数),调用可以写成
with Restorer('x'):
那么恢复器可以是这样的(省略错误检查):
class Restorer:
def __init__(self, varName):
self.varName = varName
def __enter__(self):
self.oldValue = globals()[self.varName]
def __exit__(self, exc_type, exc_val, exc_tb):
globals()[self.varName] = self.oldValue
利用 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
您可以滥用 class
语句来引入临时 "scope":
x = 5
class Foo:
print(x)
x = 6
print(x)
print(x)
这个 "works" 因为 Foo
没有建立一个真正的新范围,这意味着第一个 print(x)
指的是当前范围内的名称 x
,但是在临时无人区分配以准备创建同名的 class 属性,该属性用于正文的其余部分。但是,我相信这足以模拟您的要求。
(也就是说,实际上不要在实践中使用它。如果您需要某种临时覆盖,请编写适当的函数或手动保存值。)
这更多地与名称的范围有关,而不是与变量有关。
您可以通过创建具有块行为的函数来创建作用域:
def behaviour():
x = 6
...
x = 5
behaviour()
print(x)
输出:
5
或者,您可以引入一个新名称:
x = 5
y = 6
...
print(x)
输出:
5
您将如何编写上下文管理器来将变量恢复为其原始值?例如:
x = 5
with Restorer(x):
x = 6
...
print(x)
输出将是: 5
这只有在特定情况下才有可能。通常上下文管理器只获取x
的值(实际上是引用)。它无法访问变量本身。
对于全局变量,如果调用函数定义在同一个模块中(或者代码只是放在同一个模块中,没有周围的函数),调用可以写成
with Restorer('x'):
那么恢复器可以是这样的(省略错误检查):
class Restorer:
def __init__(self, varName):
self.varName = varName
def __enter__(self):
self.oldValue = globals()[self.varName]
def __exit__(self, exc_type, exc_val, exc_tb):
globals()[self.varName] = self.oldValue
利用 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
您可以滥用 class
语句来引入临时 "scope":
x = 5
class Foo:
print(x)
x = 6
print(x)
print(x)
这个 "works" 因为 Foo
没有建立一个真正的新范围,这意味着第一个 print(x)
指的是当前范围内的名称 x
,但是在临时无人区分配以准备创建同名的 class 属性,该属性用于正文的其余部分。但是,我相信这足以模拟您的要求。
(也就是说,实际上不要在实践中使用它。如果您需要某种临时覆盖,请编写适当的函数或手动保存值。)
这更多地与名称的范围有关,而不是与变量有关。
您可以通过创建具有块行为的函数来创建作用域:
def behaviour():
x = 6
...
x = 5
behaviour()
print(x)
输出:
5
或者,您可以引入一个新名称:
x = 5
y = 6
...
print(x)
输出:
5