How to override __setitem__ for globals dict function?

I want to be able to intercept the assignment of variables inside a function and execute my own code. I tried to create a custom dict as follows:

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

If I execute code using this as a global dict, then my custom code will run every time a variable is assigned. eg:.

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

But if my code is inside a function, it does not work:

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

In this case, an โ€œxโ€ is assigned, but my custom code does not start. I assume that inside the function, the global dict changes somehow without calling setitem. It's right? Is there a way to intercept variable assignments inside a function and execute custom code?

I want to do this in order to synchronize some objects available inside the function with other objects in my program. In the case of words, when a function assigns to certain variables, this change should apply to other variables in my program.

+4
source share
1 answer

The problem may be that the built-in dict methods do not cause overrides in subclasses of methods in CPython. Pypy, Jython call custom __setitem__() , so they immediately see when x set.

dis shows that STORE_GLOBAL 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 works, that is, the custom __setitem__() called.

+3
source

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


All Articles