Python: как динамически установить среду закрытия функций
Я хочу объявить функцию динамически, и я хочу обернуть любой доступ к глобальным переменным ИЛИ альтернативно определить, какие переменные являются свободными, и обернуть любой доступ к свободным переменным.
Я играю с кодом, как это:
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()
Это производит вывод:
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
Я хочу как-то поймать доступ к x
с моей диктовкой D
, Как я могу это сделать?
Я не хочу предопределять все глобальные переменные (в этом случае x
) потому что я хочу быть в состоянии загрузить их лениво.
2 ответа
То, что вы ищете, это проксирование объектов.
Вот рецепт для объектного прокси, который поддерживает хуки до и после вызова:
http://code.activestate.com/recipes/366254-generic-proxy-object-with-beforeafter-method-hooks/
Создайте подкласс, который фактически не загружает объект до тех пор, пока _pre
крючок называется. Все, что обращается к объекту, приведет к загрузке реального объекта, и все вызовы будут обрабатываться реальным объектом.
Попробуйте это
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