How to set custom locals for function call?

Chris Angelico rosuav at gmail.com
Tue Sep 1 19:01:07 EDT 2020


On Wed, Sep 2, 2020 at 8:44 AM Andras Tantos
<python-list at andras.tantosonline.com> wrote:
>
> While I'm sure you're right, it certainly is well hidden:
>
> Python 3.8.2 | packaged by conda-forge | (default, Apr 24 2020,
> 07:34:03) [MSC v.1916 64 bit (AMD64)] on win32
> Type "help", "copyright", "credits" or "license" for more information.
>  >>> locals()
> {'__name__': '__main__', '__doc__': None, '__package__': None,
> '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__':
> None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>}
>  >>> a =3
>  >>> locals()
> {'__name__': '__main__', '__doc__': None, '__package__': None,
> '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__':
> None, '__annotations__': {}, '__builtins__': <module 'builtins'
> (built-in)>, 'a': 3}
>  >>> locals()['a'] = 4
>  >>> locals()
> {'__name__': '__main__', '__doc__': None, '__package__': None,
> '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__':
> None, '__annotations__': {}, '__builtins__': <module 'builtins'
> (built-in)>, 'a': 4}
>  >>>
>
> In other words, I can indeed change the value of a local variable
> through the locals() dict.

Not quite. What you're seeing there is that there aren't any locals,
and you're getting the globals:

>>> locals() is globals()
True

In this situation, locals() DOES return a real dictionary, and it can
be manipulated as one. But only because it's the same as globals(),
and you can do all that with globals.

> I've modified my code to see if I can at
> least introduce locals through the value passed in for exec, but even
> that seems to fail:
>
> 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")
>          loc["xxx"]=123
>          glob.set_type("global")
>          glob["yyy"]=42
> exec(func.__code__, glob, loc)
> return wrapper

Your whitespace is getting messed up again, although not as badly now.
Try posting in plain text, not "rich text" or HTML or formatted text
or anything.

> It still appears to me that 'exec()' simply ignores the dict passed in
> as the local parameter: it doesn't even seem to initialize locals() from it.

I'm honestly not sure what's going on, because it's hard to follow
your code. But my suspicion is that when you exec a code object
(rather than compiling and executing a string), it's using cells/slots
rather than actually using your locals dict.

ChrisA


More information about the Python-list mailing list