Reputation: 63
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
Upvotes: 4
Views: 2457
Reputation: 24133
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
Upvotes: 0
Reputation: 531065
You can abuse a class
statement to introduce a temporary "scope":
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. 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.)
Upvotes: 0
Reputation: 10959
This is only possible under particular circumstances. Usually the context manager only gets the value (actually a reference) of 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
Upvotes: 2
Reputation: 71451
Utilizing contextlib.contextmanager
, you can reassign x
to its original value after the yield
statement:
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
Upvotes: 0