简体   繁体   English

Python Context Manager恢复变量的值?

[英]Python Context Manager to restore a variable's value?

How would you write a context manager to restore a variable to its original value? 您将如何编写上下文管理器以将变量恢复为其原始值? For example: 例如:

x = 5
with Restorer(x):
   x = 6
   ...
print(x)

Output would be: 5 输出将是:5

This is only possible under particular circumstances. 仅在特定情况下才有可能。 Usually the context manager only gets the value (actually a reference) of x . 通常,上下文管理器仅获取x的值(实际上是引用)。 It gets no access to the variable itself. 它无法访问变量本身。

For global variables if the calling function is defined in the same module (or the code is just placed in the same module without surrounding function) the call can be written as 对于全局变量,如果调用函数在同一模块中定义(或者代码仅放置在同一模块中而不包含周围的函数),则调用可以写为

with Restorer('x'):

Then the restorer can be something like (error checking omitted): 然后,恢复器可能类似于(省略错误检查):

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

Utilizing contextlib.contextmanager , you can reassign x to its original value after the yield statement: 利用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)

Output: 输出:

5
in contextmanager: 6
outside contextmanager 5

You can abuse a class statement to introduce a temporary "scope": 您可以滥用class声明来引入临时“作用域”:

x = 5
class Foo:
    print(x)
    x = 6
    print(x)
print(x)

This "works" because Foo doesn't establish a true new scope, meaning the first print(x) refers to the currently in-scope name x , but the assignment in a temporary no-man zone in preparation to create a class attribute by the same name, and that attribute is used for the remainder of the body. 之所以可行,是因为Foo并没有建立真正的新作用域,这意味着第一个print(x)引用了当前作用域内的名称x ,而是在一个临时的无人区域进行赋值,以通过以下方式创建类属性名称相同,并且该属性用于正文的其余部分。 However, that is, I believe, sufficient to simulate what you are asking for. 但是,我相信这足以模拟您的要求。

(That said, don't actually use this in practice. Write proper functions, or save values manually, if you need some sort of temporary override.) (也就是说,实际上不要实际使用它。如果需要某种临时替代,请编写适当的函数或手动保存值。)

This is more to do with the scope of names than variables. 这更多是与名称范围有关,而不是变量。

You can create scope by creating a function with the behaviour for the block: 您可以通过创建具有该块行为的函数来创建作用域:

def behaviour():
    x = 6
    ...

x = 5
behaviour()
print(x)

Output: 输出:

5

Alternatively, you could just introduce a new name: 另外,您可以引入一个新名称:

x = 5
y = 6
...
print(x)

Output: 输出:

5

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM