-
-
Notifications
You must be signed in to change notification settings - Fork 30.8k
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
gh-119180: Set the name of the param to __annotate__ to "format" #124730
Merged
Merged
Changes from all commits
Commits
Show all changes
7 commits
Select commit
Hold shift + click to select a range
02770d7
gh-119180: Set the name of the param to __annotate__ to "format"
JelleZijlstra 68324ef
fix pydoc
JelleZijlstra 2dae0d0
Add tests
JelleZijlstra c51b8d0
Merge remote-tracking branch 'upstream/main' into coformatname
JelleZijlstra 90a35be
more tests
JelleZijlstra b6cbb87
reword comment
JelleZijlstra c30a54d
Merge branch 'main' into coformatname
JelleZijlstra 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
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
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
Oops, something went wrong.
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.
This isn't a critique of your approach, but--I'm surprised you needed to go to all this effort. Why was it necessary to make a new tuple, write the new value for index 0, copy over the other values, and release the reference to the old tuple? I'm assuming the reference count of
co_localsplusnames
is currently 1; I would have asserted that, then overwritten the first entry. I grant you your approach is more conceptually hygienic, but in practice I assume the quick-and-dirty approach would work equally well.What am I missing?
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.
While it is possible to mutate tuples in C code, it feels riskier. For example, maybe we'll make changes in the future that rely on tuples being immutable.
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 assure you, this is a long-standing CPython idiom. We've relied on "if there's only one reference to an object, and you own it, you may modify the object however you like" for decades now.
For fun I made a survey of CPython, literally examining every instance of
PyTuple_SET_ITEM
. (I didn't try the other spellings.) I found a bunch of sites where we do this. In nearly every instance the code is structured as follows:(I'll append the list of such sites at the bottom of this comment.)
Clearly these existing sites are optimizations; instead of destroying the old tuple and creating a fresh one, they're just reusing the existing tuple. They have a harder time of it because generally the tuple has been shown to the interpreter. In our case, we have a freshly compiled code object that hasn't been shown to the interpreter. So there's no chance anyone else has taken any references yet.
If we did change CPython so this was no longer viable, the developer making that change would have to fix all the sites I listed below, which they would probably find the same way I did--looking for all places where people set things in tuples. I don't think modifying the tuple directly would trip up such a future developer.
So, yeah, I really do think it'd be safe to modify the tuple in-place. Just to be totally safe, I'd check the reference count was 1 and raise if it wasn't. (It'd only happen if someone was hacking on
compile.c
or something, at which point they would deal with it. This would never raise in the wild.)I don't actually mind you doing it the hard way--we can ship it like this. It just seems needless. We have a longstanding idiom that lets us skip the laborious approach you took. But I'm not gonna fight you about it.
Places where CPython modifies tuples in-place:
compile.c
does it a couple times in its internal cache objects. Never exposed to the user (I think).zip_next
in bltinmodule.c, uses_PyObject_IsUniquelyReferenced
.odictiter_iternext
inodictobject.c
, uses(Py_REFCNT(result) == 1)
.enum_next_long
inenumobject.c
, usesif (Py_REFCNT(result) == 1)
.dictiter_iternextitem
indictobject.c
, uses_Py_IsOwnedByCurrentThread
.dictreviter_iter_lock_held
indictobject.c
, usesPy_REFCNT(result) == 1
.intern_constants
incodeojbect.c
, doesn't check ownership, this is incon->consts
and I assume that's internal.Five places in
itertoolsmodule.c
:pairwise_next
combinations_next
cwr_next
permutations_next
zip_longest_next
, all usePy_REFCNT(result) == 1
.p.s. you should see the if-only-one-reference-modify-the-object shenanigans in the Unicode object!
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.
See #127058 where @markshannon proposes to deprecate existing tuple-mutation shenanigans. That strengthens my conviction that we shouldn't introduce a new tuple mutation here.