Playing with variables in Python
10 Jul 2017Trying again to hack the Python language itself, I will publish in this post two little pieces of code for tweaking the scope of global variables.
The first one is a decorator “freezing” some global variables to their current value at the time a function is defined.
def protect(*A):
def D(f):
protected = {}
for k in A: protected[k] = globals()[k]
def wrapper(*args, **kwargs):
previous = {}
g = globals()
for k in A:
if k in g: previous[k] = g[k]
for k in A: g[k] = protected[k]
try:
out = f(*args, **kwargs)
except Exception:
for k in A:
if k in previous: g[k] = previous[k]
else: del g[k]
raise
for k in A:
if k in previous: g[k] = previous[k]
else: del g[k]
return out
return wrapper
return D
Let’s try it:
a = 42
@protect("a")
def test(n):
return a*n
print(test(15))
a=5
print(test(15))
should print twice the value 630 despite the fact the global variable a
has been redefined in the meantime.
The second piece of code is a context manager mimicking the behaviour of the let
function in Lisp-like languages:
class RestrictedScope():
def __init__(self, scope):
self.scope = scope
def __enter__(self):
self.p = {}
g = globals()
for k in self.scope:
if k in g: self.p[k] = g[k]
g[k] = self.scope[k]
def __exit__(self, *a):
g = globals()
for k in self.scope:
if k in self.p: g[k] = self.p[k]
else: del g[k]
This context manager temporarily hides global variables, restoring them to their current state as soon as the context is left:
a = 42
def test(n):
return a*n
print(test(10))
with RestrictedScope({"a": 10}):
print(test(10))
print(test(10))