I apologize. This does indeed not work. What does work, however, is setting a variable from a tracing function. There is magic in the tracing machinery that writes back the variables to the frame when the tracing function returns. This causes the bug referenced as [1] in both PEPs, and both propose to fix the bug by not writing things back that way, instead writing back whenever a key in the proxy is set. The discussion is about subtler differences between the proposals.
—Guido
On Sat, Aug 21, 2021 at 05:46:52PM -0700, Guido van Rossum wrote:
> Hopefully anyone is still reading python-dev.
I am :-)
[...]
> Everything here is about locals() and f_locals in *function scope*. (I use
> f_locals to refer to the f_locals field of frame objects as seen from
> Python code.) And in particular, it is about what I'll call "extra
> variables": the current CPython feature that you can add *new* variables to
> f_locals that don't exist in the frame, for example:
>
> def foo():
> x = 1
> locals()["y"] = 2 # or sys._getframe()["y"] = 2
I'm confused. I don't think it currently works, at least not in the
sense that I understand "works" to mean. Sure, you can add a new key to
the dict, but that doesn't add a new local variable:
>>> def spam():
... if False: y = 0 # Fool the compiler into treating y as a local.
... x = 0
... locals()['y'] = 1
... print(sys._getframe().f_locals)
... print(y)
...
>>> spam()
{'x': 0}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 6, in spam
UnboundLocalError: local variable 'y' referenced before assignment
Am I missing something? The above is in 3.9, has something changed in
3.10 or am I just misunderstanding what you mean by "works"?
Using f_locals instead of locals() doesn't change the UnboundLocalError
in my testing.
If you are not referring to new local variables, then I don't understand
what these "extra variables" are or where they live in the current
implementation.
A recent thread on Discuss is maybe relevant:
https://discuss.python.org/t/how-can-i-use-exec-in-functions-in-python3-6-similar-to-python2-7/10191
Would either of these two proposals re-enable exec to work inside
functions as it used to?
I think Nick's PEP 558 does not, it wants to make it explicit that
changes to locals will not be reflected in the local variables. Although
Nick does refer to a "write back" strategy that apparently works *now*.
That suggests:
- there currently is a trick to writing new local variables in the
function namespace;
- and Nick's PEP will break it.
Am I correct?
Mark's PEP 667 says "However f.f_locals == f.f_locals will be True, and
all changes to the underlying variables, by any means, will be always be
visible" so I think that means it will allow exec to work as in
Python2.x, at least if you pass sys._getframe().f_locals to exec instead
of locals().
Perhaps we need an informational PEP to explain how local variables
inside functions work now :-)
--
Steve
_______________________________________________
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-leave@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/CREZXKZWVSICQY4WHKUPXGJU67UUPQZ2/
Code of Conduct: http://python.org/psf/codeofconduct/
--
--Guido (mobile)