Context manager to save/restore a name binding

Peter Otten __peter__ at web.de
Fri Aug 31 02:27:13 EDT 2012


Ben Finney wrote:

> I have written a context manager to save and restore a name binding::
> 
>     import contextlib
> 
>     @contextlib.contextmanager
>     def preserve_value(namespace, name):
>         """ A context manager to preserve, then restore, the specified
>         binding.
> 
>             :param namespace: The namespace object (e.g. a class or dict)
>                 containing the name binding.
>             :param name: The name of the binding to be preserved.
>             :yield: None.
> 
>             When the context manager is entered, the current value bound
>             to `name` in `namespace` is saved. When the context manager is
>             exited, the binding is re-established to the saved value.
> 
>             """
>         saved_value = getattr(namespace, name)
>         yield
>         setattr(namespace, name, saved_value)
> 
> The use case is <URL: http://stackoverflow.com/a/6811921/70157>, where
> it's used like this::
> 
>     with preserve_value(sys, 'dont_write_bytecode'):
>         sys.dont_write_bytecode = True
>         module = imp.load_module(…)
> 
> That way, I can set ‘sys.dont_write_bytecode’ to the value I need in
> this part of the code, knowing that however the code continues the
> previous value of that setting will be restored to whatever it was
> before I touched it.
> 
> Have I re-invented a context manager which already exists? Is there a
> better way to do what ‘preserve_value’ is doing?
 
You should wrap yield in a try ... finally. You might allow setting the new 
value in the manager (untested):

import contextlib
missing = object()

@contextlib.contextmanager
def preserve_attr(namespace, name, value=missing):
    saved_value = getattr(namespace, name)
    if value is not missing:
        setattr(namespace, name, value)
    try:
        yield
    finally:
        setattr(namespace, name, saved_value)





More information about the Python-list mailing list