How to override __setitem__ for a function's globals dict?

允我心安 提交于 2019-12-12 12:08:24

问题


I want to be able to intercept variable assignments within a function and execute custom code. I have tried creating a custom dict as follows:

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

If I exec code using this as the global dict, then my custom code will run on each variable assignment. e.g.:

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

But if my code is inside a function, it doesn't work:

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

In this case, 'x' is assigned, but my custom code does not run. I assume that within a function, the global dict is being modified somehow without calling setitem. Is this correct? Is there a way to intercept variable assignments within a function and execute custom code?

I want to do this in order to synchronize certain objects available inside a function with other objects in my program. In order words, when the an assignment to certain variables occurs inside the function, that change should propagate to other variables in my program.


回答1:


The issue might be that builtin dict methods don't call overridden in subclasses methods in CPython. Pypy, Jython call custom __setitem__() so they see immediately when x is set.

dis module shows that STORE_GLOBAL is used to set 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

It is implemented in ceval.c as:

    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;

if PyDict_SetItem() is replaced with PyObject_SetItem() then CPython also works i.e., custom __setitem__() is called.



来源:https://stackoverflow.com/questions/13259749/how-to-override-setitem-for-a-functions-globals-dict

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!