Snipping old parts...
On 9/1/20 4:01 PM, Chris Angelico wrote:
On Wed, Sep 2, 2020 at 8:44 AM Andras Tantos
<python-l...@andras.tantosonline.com> wrote:
While I'm sure you're right, it certainly is well hidden:
...
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.
That could very well be the case.
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:
...
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.
OK, and sorry about that. May third time a charm?
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")
loc["xxx"] = 123
glob.set_type("global")
glob["yyy"] = 42
exec(func.__code__, glob, loc)
return wrapper
@mylocals
def fun1():
print("locals at the beginning:")
print(", ".join(f"{name}: {value}" for name, value in
locals().items()))
print("globals at the beginning:")
print(", ".join(f"{name}: {value}" for name, value in
globals().items()))
print(f"fun1 with locals: {type(locals())} and globals:
{type(globals())}")
a = 1
b = 2
c = 3
a = b
c = 5
print("locals at the end:")
print(", ".join(f"{name}: {value}" for name, value in
locals().items()))
print("globals at the end:")
print(", ".join(f"{name}: {value}" for name, value in
globals().items()))
fun1()
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
Thanks for all the help!
Indeed, I'm executing a code object and not a string. Is there any way
to get to the string version of the function and force a re-compile of
it during an exec? Would it help?
I guess if I was doing that, I would need to execute the 'body' of the
function within the exec and by passing in a local parameter I can
pretend it has its own call-stack entry. But is that truly equivalent to
calling the original function?
It seems to me that even it were all possible, the solution would be
very brittle, for example, additional decorators would mess things up.
Though that's probably the case independent of the
code-object/source-code distinction.
Andras
--
https://mail.python.org/mailman/listinfo/python-list