How to set custom locals for function call?

MRAB python at mrabarnett.plus.com
Tue Sep 1 15:41:22 EDT 2020


On 2020-09-01 05:45, Andras Tantos wrote:
> All,
> 
> I'm new here, so please direct me to the right forum, if this is not the
> one...
> 
> What I'm trying to do is 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.
> 
> |classMySymbolTable(dict):defset_type(self,t):self.type =t
> def__getitem__(self,key):print(f"Requesting key {key} from {self.type}
> table")returnsuper().__getitem__(key)def__setitem__(self,key,value):print(f"Setting
> key {key} from {self.type} table to value
> {value}")returnsuper().__setitem__(key,value)defmylocals(func):defwrapper(*args,**kwargs):loc
> =MySymbolTable()glob
> =MySymbolTable(globals())loc.set_type("local")glob.set_type("global")exec(func.__code__,glob,loc)returnwrapper
> @mylocalsdeffun1():print(f"fun1 with locals: {type(locals())} and
> globals: {type(globals())}")a =1b =2c =3a =b c =5fun1()|
> 
> However, when I run it, I get the following output:
> 
> |Requestingkey printfromglobaltable Requestingkey type fromglobaltable
> Requestingkey locals fromglobaltable Requestingkey type fromglobaltable
> Requestingkey globals fromglobaltable fun1
> withlocals:<class'dict'>andglobals:<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?
> 
CPython is able to identify all of the local names of a function and, 
basically, for reasons of efficiency, it uses slots for the local names 
instead of an actual dict. 'locals()' just returns a dict that 
represents those local names and their current values, but modifying 
that dict has no effect on the actual local names. In short, there isn't 
really a local dict that you can replace.


More information about the Python-list mailing list