-
Notifications
You must be signed in to change notification settings - Fork 232
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow function definition locals() to be modified in the shell #571
Draft
asmeurer
wants to merge
4
commits into
inducer:main
Choose a base branch
from
asmeurer:editable-locals
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 3 commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
5b9d94f
Allow function definition locals() to be modified in the shell
asmeurer c5d17fd
Revert change to IPython shell to make locals editable
asmeurer 95ef370
Make the var view update when executing a command in the internal shell
asmeurer 82b1f15
Add a comment explaining the curframe_locals behavior
asmeurer File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add a comment explaining what it's good for? TBH, I'm not sure I understand why the proposed changes have the described effect. (at least with just looking at the diff)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might try to dig deeper to figure out exactly what is going on. From what I can tell, as long as you reuse the same locals object, any modifications you make to it are reflected when the frame is run. But if you access
frame.f_locals
again, it recomputes the locals and resets them. I'm unclear exactly how it works, but it does.I'm actually unclear why your example at #26 (comment) didn't work for you. I tested it and even in Python 2, it has the desired effect when you set
i
on the given line.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, you've nerd-sniped me. Grr. 🙂
Here's what I've found so far:
f_locals
winds up here: https://github.com/python/cpython/blob/c450c8c9ed6e420025f39d0e4850a79f8160cdcd/Objects/frameobject.c#L25-L32f_locals
, which is the same object every time you access it, here: https://github.com/python/cpython/blob/v3.11.0/Objects/frameobject.c#L1097f_locals
make their way from there back to the "fast" local variable storage. I lost the trail atPyFrame_LocalsToFast
, in that I wasn't totally able to pin down what causes it to get called.Some notes:
PyFrame_LocalsToFast
here.Whatever we do here, we should make sure to preserve a summary of it in comments, so that we don't have to rediscover it some other time.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found https://peps.python.org/pep-0558/, which mentions this behavior (footnote 3), although the link there is broken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That PEP is very technical, but I think what happens is:
1
instead of2
.frame.f_locals
is designed to be a write-through proxy (probably exactly for this feature).f_locals
computes this write-through proxy from a snapshot. That means that when you access it, it recomputes it from what it was, and throws away whatever was there before. Since it's a write-through proxy, this effectively resets the locals in the frame.But I'm not completely sure about this. Honestly I think a core dev would need to confirm the details. I think I'll just cross-reference this PEP in the comments since that should be a good jumping off point for anyone who is interested in what is going on.