2012-11-06 44 views
4

我希望能够拦截函数中的变量赋值并执行自定义代码。我曾尝试创建一个自定义字典如下:如何覆盖__setitem__函数的全局字典?

class userdict(dict): 
    def __setitem__(self, key, value): 
     print 'run my code' 
     dict.__setitem__(self, key, value) 

如果我用这个作为全球字典EXEC代码,然后我的自定义代码将在每个变量赋值运行。例如: -

UserDict = userdict() 
exec 'x = 1' in UserDict 
#outputs 'run my code' 

但是,如果我的代码是一个函数里面,这是行不通的:

code = """ 
def foo(): 
    global x 
    x = 1 
""" 
exec code in UserDict 
UserDict['foo']() 

在这种情况下,“X”分配,但我的自定义代码不能运行。我认为在一个函数内,全局字典正在被修改,而不用调用setitem。它是否正确?有没有办法拦截函数中的变量赋值并执行自定义代码?

我想这样做是为了将函数中可用的某些对象与程序中的其他对象同步。换句话说,当某个变量的赋值出现在函数内部时,该变化应该传播到我的程序中的其他变量。

+3

这听起来很邪恶。 – jdi

+0

你试图重写分配给全局变量时会发生什么,或者你还想在分配给局部变量时挂钩吗?两者都不是一个好主意,但前者可能有一些脆弱的,偷偷摸摸的黑客攻击。后者可能不可能。 – BrenBarn

+0

你不能用你自己的障碍替换全局模块字典,并期望它可以工作。实际上应该发生的是这些函数应该发出某种信号或回调以允许其他数据结构进行响应。它不应该是一个黑盒子的情况,变量只是随机改变你。 – jdi

回答

3

此问题可能是内置的dict方法在CPython中的子类方法中未被重写。 Pypy,Jython调用自定义__setitem__(),让他们在x被设置时立即看到。

dis模块显示STORE_GLOBAL用于设置x

>>> def f(): 
...  global x 
...  x = 1 
... 
... 
>>> import dis 
>>> dis.dis(f) 
    4   0 LOAD_CONST    1 (1) 
       3 STORE_GLOBAL    0 (x) 
       6 LOAD_CONST    0 (None) 
       9 RETURN_VALUE 

它在ceval.c实现为:

TARGET(STORE_GLOBAL) 
     w = GETITEM(names, oparg); 
     v = POP(); 
     err = PyDict_SetItem(f->f_globals, w, v); 
     Py_DECREF(v); 
     if (err == 0) DISPATCH(); 
     break; 

如果PyDict_SetItem()替换PyObject_SetItem()然后CPython中也适用,即,定制__setitem__()叫做。

+0

+1进行详细分析。 –

+0

谢谢。由于这是不同的python实现之间的东西,我想我会远离我的程序依赖于它:-) – user1804375