On 9/1/20 5:31 PM, Chris Angelico wrote:
On Wed, Sep 2, 2020 at 10:23 AM Andras Tantos
<python-l...@andras.tantosonline.com> wrote:
I did see these macros in the CPython source code. What it seems to
imply is that if I wanted to do what I intend, that is to hook every
local variable assignment, I would have to modify the AST. That seems
rather more effort than simply supplying my own locals dictionary. I
will try to look myself as well, but do you have an inkling as to how
complex would it be to convince CPython to optimize locals only if no
custom locals is provided during exec?
To my untrained eye, it seems to be an unsafe optimization that breaks
the contract of the exec API.
By the time you're calling exec, it's too late to decide whether to
optimize, since you're using a precompiled code object. If you want
that behaviour, try exec'ing a string of code instead.
ChrisA
I guess, it depends. I can think of several ways of dealing with this.
Probably the highest performant version would be to generate byte-code
along these lines for every function body:
if <<custom locals is specified>>:
<<code with no SETLOCAL/GETLOCAL optimization>>
else:
<<code with SETLOCAL/GETLOCAL optimization>>
This of course makes the byte-code about twice as large as today.
One could also patch up the SETLOCAL/GETLOCAL macros to test for this
condition, in which case no byte-code changes are needed, but
performance would degrade because of all the - normally unnecessary -
checks.
There's also a possibility of detecting this condition within the
underlying C implementation of exec() and trigger a re-generation of the
byte-code from source.
I don't feel confident enough to even attempt anything but the middle
approach, but even then: this is a change to CPython, obviously
something that needs community vetting and approval.
Reacting to your last sentence: I have investigated how to get the
source code, given a function object, but the best I could come up with is:
1. Retrieve the source code for the function, using inspect.getsource()
2. massage it to contain only the function body (that is to remove
the def ... line)
3. pass that to exec.
With that, I finally have been able to get locals work, but here, I'm
back to the other case, where I essentially promoted the body of the
function into the global namespace, so now locals() and globals() are
the same thing. This is hardly the same context in which the function
would originally execute.
Andras
--
https://mail.python.org/mailman/listinfo/python-list