Temporary variables in Python
Very easy using context managers!
The functions locals() and globals() return dictionaries containing the
variables that are defined in the current local or global scope. What is cool is
that variables can be declared, modified, and “undeclared” by modifying these
dictionaries (see a tutorial here)!
To get a temporary variable, we can therefore build a context manager that adds and removes a variable to either the local or the global definitions, for example:
class TemporaryVariables:
    def __init__(self, dest, **kwargs):
        # dest is a dictionary, either from locals() or globals()
        # kwargs are the variables to define, and their values
        self._vars = kwargs
        self._old = dest
        self._backup = {}
        for k, v in self._vars.items():
            # for each variable...
            if k in self._old:
                # store the old value if overwriting
                self._backup[k] = self._old[k]
            # and set the new value
            self._old[k] = v
    def __enter__(self, *args, **kwargs):
        pass
    def __exit__(self, exc_type, exc_val, exc_tb):
        for k, v in self._vars.items():
            # for each variable...
            if k in self._backup:
                # restore the old value if it was overwritten
                self._old[k] = self._backup[k]
            else:
                # or "undefine" the variable if it was new
                self._old.pop(k)
Here’s how you would use this:
a = 'hello'
print(a)
with TemporaryVariables(locals(), a='world'):
    a = a + '!'
    print(a)
print(a)
Which prints:
hello
world!
hello
Due to the way we took the backup, variables that were not defined before the
with block remain undefined after it, too:
with TemporaryVariables(locals(), x=42):
    print(x)
print(x)  # x was only defined in the with block
We now get an error when using x after whe with:
42
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [8], line 3
      1 with TemporaryVariables(locals(), x=42):
      2     print(x)
----> 3 print(x)
NameError: name 'x' is not defined
Finally, notice the difference between local and global scoping:
def f():
    print('inside f with b =', b)
def scope_test():
    with TemporaryVariables(globals(), b=2) as q:
        f()
    with TemporaryVariables(locals(), b=2) as q:
        f()
scope_test()
Now, only the variable b that is defined in the global scope can be used in
functions called from within the with:
inside f, with b = 2
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
Cell In [9], line 13
     10     with TemporaryVariables(locals(), b=2) as q:
     11         f()
---> 13 scope_test()
Cell In [9], line 11, in scope_test()
      7     f()
     10 with TemporaryVariables(locals(), b=2) as q:
---> 11     f()
Cell In [9], line 2, in f()
      1 def f():
----> 2     print('inside f, with b =', b)
NameError: name 'b' is not defined
Happy hacking!