Python: how to dynamically set a function closure environment

I want to declare a function dynamically, and I want to wrap any access to global variables OR alternatively determine which variables are free, and wrap any access to free variables.

I play with code like this:

class D: def __init__(self): self.d = {} def __getitem__(self, k): print "D get", k return self.d[k] def __setitem__(self, k, v): print "D set", k, v self.d[k] = v def __getattr__(self, k): print "D attr", k raise AttributeError globalsDict = D() src = "def foo(): print x" compiled = compile(src, "<foo>", "exec") exec compiled in {}, globalsDict f = globalsDict["foo"] print(f) f() 

This leads to the output:

 D set foo <function foo at 0x10f47b758> D get foo <function foo at 0x10f47b758> Traceback (most recent call last): File "test_eval.py", line 40, in <module> f() File "<foo>", line 1, in foo NameError: global name 'x' is not defined 

What I want will somehow catch access to x with my dictate-like wrapper D How can i do this?

I don't want to predefine all global variables (in this case x ), because I want them to be lazily loaded.

+6
source share
2 answers

What you are looking for is object proxies> .

Here is the recipe for the proxy object that supports cross and post calls:

http://code.activestate.com/recipes/366254-generic-proxy-object-with-beforeafter-method-hooks/

Create a subclass that does not actually load the object until the _pre hook is _pre . Any call to the object will lead to loading the real object, and all calls will be processed directly by the real object.

+2
source

try it

 class GlobalDict(object): def __init__(self, **kwargs): self.d = kwargs def __getitem__(self, key): print 'getting', key return self.d[key] def __setitem__(self, key, value): print 'setting', key, 'to', value if hasattr(value, '__globals__'): value.__globals__.update(self.d) self.d[key] = value for v in self.d.values(): if v is not value: if hasattr(v, '__globals__'): v.__globals__.update(self.d) def __delitem__(self, key): print 'deling', key del self.d[key] for v in self.d.values(): if hasattr(v, '__globals__'): del v.__globals__[key] >>> gd = GlobalDict() >>> src = 'def foo(): print x' >>> compiled = compile(src, '<foo>', 'exec') >>> exec compiled in {}, gd setting foo to <function foo at 0x102223b18> >>> f = gd['foo'] getting foo >>> f <function foo at 0x102223b18> >>> f() # This one will throw an error Traceback (most recent call last): File "<input>", line 1, in <module> File "<foo>", line 1, in foo NameError: global name 'x' is not defined >>> gd['x'] = 1 setting x to 1 >>> f() 1 >>> del gd['x'] # removes 'x' from the globals of anything in gd >>> f() # Will now fail again Traceback (most recent call last): File "<input>", line 1, in <module> File "<foo>", line 1, in foo NameError: global name 'x' is not defined 
+1
source

Source: https://habr.com/ru/post/893367/


All Articles