-
-
Notifications
You must be signed in to change notification settings - Fork 31.9k
gh-95337: update TypeVarTuple example #95338
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
Conversation
Notice that "T" is only used once in the function signature, which Pylance will highlight as an error. In this case, Any is just as meaningful as T (and I would argue semantically better, we don't care what the first element is) All of the examples (checked with reveal_type) are still valid.
@mrahtz @pradeep90 Do you agree? |
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.
In this case, Any is just as meaningful as T (and I would argue semantically better, we don't care what the first element is)
I'm against removing the T
. It's there to demonstrate how tuples are split into T
and *Ts
and what each variable is bound to. Otherwise, there's nothing in the docs to show this key behavior.
Given that this example is for explanation, I don't think we should change it just to avoid Pylance lint errors.
Notice that "T" is only used once in the function signature, which Pylance will highlight as an error.
If you feel really strongly about the lint error, you could change it to split_first_and_rest(xs: tuple[T, *Ts]) -> tuple[T, tuple[*Ts]]: ...
. But that complicates the introduction to a concept that can already be hard to understand. I think the example is fine as it is.
That's fair, I wasn't trying to pose that as a substantial point, that's just how I noticed it.
Then I think we should change the example to fully demonstrate that behavior (i.e. the more complicated version you just proposed or similar). As is, that behavior is encoded in comments but not the code. Personally I think |
Sorry for the slow reply - busy week. I agree with:
To put it another way, I think it's important to emphasise that TypeVarTuples aren't anything 'special' - that the mental model is "TypeVarTuples just unpack into something that looks like a bunch of TypeVars, so it can be used with other regular TypeVars" - as opposed to "TypeVarTuple is this special thing that needs to be used on its own and I have to arbitrarily star", which is the nuance I think a reader might get from def remove_first_element(tup: tuple[Any, *Ts]) -> tuple[*Ts]:
return tup[1:] (Ok, yes, this example does at least mix a TypeVarTuple with an Any - but that might not be enough to give the impression that TypeVarTuples can also be mixed with regular TypeVars.) Having said that, I also agree with:
More than just fixing Pylance lint, I do think it's important our examples implicitly instruct the user in what kinds of things are valid to do. Since (iiuc?) most type checkers do enforce this thing that it's not valid to have an unreferenced type variable, I think it would be good to avoid giving the user the impression that this might be possible.
It does make it more complicated, but only a little bit - iiuc: def move_first_element_to_last(tup: tuple[T, *Ts]) -> tuple[*Ts, T]:
return (*tup[1:], tup[0]) If the reader understands the splitting of Having said that, I don't feel strongly about this, so Pradeep, if you still have hesitations, I trust your judgement, and we can leave it as it is. |
Thank you for the feedback folks. It sounds like the consensus is that if there was going to be a change made it would be in the direction of the more complex example that uses the type var in the return type, so I'll at least change this PR to propose that instead of using Any. |
I like Matthew's idea of having the example move the first tuple element to the end: it's a fairly realistic example and yet not too complicated. |
That's a great example @mrahtz , I had missed it. I like that it also uses For completeness, I added the invalid case of |
Co-authored-by: Alex Waygood <[email protected]>
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 like this PR!
Co-authored-by: Alex Waygood <[email protected]>
Doc/library/typing.rst
Outdated
|
||
# T is bound to int, Ts is bound to () | ||
# Return value is (), which has type tuple[()] | ||
remove_first_element(tup=(1,)) | ||
# Return value is (1, ), which has type tuple[int] |
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.
Nit: I think PEP 8 says there shouldn't be a space after the comma here: (1,)
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.
done ✅
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.
Lgtm. Thanks, Adrian!
Thanks @adriangb for the PR, and @JelleZijlstra for merging it 🌮🎉.. I'm working now to backport this PR to: 3.10, 3.11. |
Sorry, @adriangb and @JelleZijlstra, I could not cleanly backport this to |
GH-96431 is a backport of this pull request to the 3.11 branch. |
Co-authored-by: Alex Waygood <[email protected]> (cherry picked from commit 07f12b5) Co-authored-by: Adrian Garcia Badaracco <[email protected]>
Oops, my bad, no TypeVarTuples in 3.10 |
Co-authored-by: Alex Waygood <[email protected]> (cherry picked from commit 07f12b5) Co-authored-by: Adrian Garcia Badaracco <[email protected]>
Notice that "T" is only used once in the function signature, which Pylance will highlight as an error.
In this case, Any is just as meaningful as T (and I would argue semantically better, we don't care what the first element is)
All of the examples (checked with reveal_type) are still valid.