I'm trying to call a function, but monitor all the local variable accesses within that function. What I thought I would need to do, is to exec the function with a custom locals dictionary. The code below attempts to do it.
class MySymbolTable(dict):
def set_type(self, t):
self.type = t
def __getitem__(self, key):
print(f"Requesting key {key} from {self.type} table")
return super().__getitem__(key)
def __setitem__(self, key, value):
print(f"Setting key {key} from {self.type} table to value {value}")
return super().__setitem__(key, value)
def mylocals(func):
def wrapper(*args, **kwargs):
loc = MySymbolTable()
glob = MySymbolTable(globals())
loc.set_type("local")
glob.set_type("global")
exec(func.__code__, glob, loc)
return wrapper
@mylocals
def fun1():
print(f"fun1 with locals: {type(locals())} and globals: {type(globals())}")
a = 1
b = 2
c = 3
a = b
c = 5
fun1()
However, when I run it, I get the following output:
Requesting key print from global table
Requesting key type from global table
Requesting key locals from global table
Requesting key type from global table
Requesting key globals from global table
fun1 with locals: <class 'dict'> and globals: <class '__main__.MySymbolTable'>
That is to say, global accesses are redirected to my custom dict, but local assignments are not. You can even see that in the types of the two objects printed in the last line.
My hunch is that since I'm using the functions __code__ member, I end up executing pre-compiled byte-code which has already assumptions about the locals dict built into it.
If I'm right (or even if I'm not), what is the right way to achieve my goal: that local assignments get redirected to the supplied dictionary?
Thanks!