I often find that I need to assign some member variables temporarily, e.g.
old_x = c.x
old_y = c.y
# keep c.z unchanged
c.x = new_x
c.y = new_y
do_something(c)
c.x = old_x
c.y = old_y
but I wish I could simply write
with c.x = new_x; c.y = new_y:
do_something(c)
or even
do_something(c with x = new_x; y = new_y)
Can Python's decorators or other language features enable this kind of pattern? (I could modify c
's class as needed)
Context managers may be used for it easily.
Quoting official docs:
Typical uses of context managers include saving and restoring various kinds of global state, locking and unlocking resources, closing opened files, etc.
It seems like saving and restoring state is exactly what we want to do here.
Example:
from contextlib import contextmanager
@contextmanager
def temporary_change_attributes(something, **kwargs):
previous_values = {k: getattr(something, k) for k in kwargs}
for k, v in kwargs.items():
setattr(something, k, v)
try:
yield
finally:
for k, v in previous_values.items():
setattr(something, k, v)
class Something(object):
def __init__(self, x, y):
self.x = x
self.y = y
def say_hello(self):
print("hello", self.x, self.y)
s = Something(1, 2)
s.say_hello() # hello 1 2
with temporary_change_attributes(s, x=4, y=5):
s.say_hello() # hello 4 5
s.say_hello() # hello 1 2