How to set custom locals for function call?

Chris Angelico rosuav at gmail.com
Tue Sep 1 16:42:10 EDT 2020


On Wed, Sep 2, 2020 at 5:00 AM Andras Tantos
<python-list at andras.tantosonline.com> 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()|

Your code's messed up in the post, so I'm guessing on how this is
actually meant to be written. Most of your whitespace has been
destroyed.

> 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.

Yes; and furthermore, CPython generally doesn't even use a dictionary
for a function's locals. Instead, it uses cells in a special array;
you can poke around with this by disassembling the code (see the
built-in "dis" module for details) and looking at the
LOAD_FAST/STORE_FAST opcodes.

You might be able to mess with this by using a closure, but local
variable references are generally considered to be an implementation
detail of the function, and it's not going to be easy to mess with
them from the outside reliably. What's the goal here?

ChrisA


More information about the Python-list mailing list