-
-
Notifications
You must be signed in to change notification settings - Fork 31.1k
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
typing.TypeVar
doesn't distinguish between (bound=None)
and not providing a bound
argument
#129543
Comments
|
AFAIK, None can be regarded as a valid sentinel but not as a valid argument to |
@picnixz I meant, it's rare for users to specify Addressing your comment about "The bound, when specified, should be a type", type-checkers are expected to follow this section of the typing specification, which allows
Many type expressions would not be instances of |
I don't think that it ever makes sense to create a |
@sobolevn there are probably some use-cases, such as in conditional definitions: if sys.version_info >= (3, 10):
TypeArg: TypeAlias = int
else:
TypeArg: TypeAlias = None
T = TypeVar("T", bound=TypeArg)
class Data(Generic[T]):
val: T |
In this case, I think the None value is not meant to be considered as a standalone type expression. Also, if the bound is NoneType, then the only possible type is NoneType right? so there is no need for a type variable I think. When I said "types" I didn't meant runtime types but rather valid type expressions, my bad.While None can be a valid standalone type expression I don't think we should support it as is for a bound of a type variable. I however wasn't aware of the exact specs so thank you I would be -0.5 on changing the default unless there is a real use case that would benefit from it (as you observed, using a None bound can be simply replaced by directly using None) |
I am afraid that those use cases are mostly artificial. Such code should rather change the genericity of the class instead or provide different class definitions if it's version-specific. |
I'm fine with leaving this with the runtime default as |
I agree with @sobolevn's comment in #129543 (comment). If we could go back in time and make it so that the
@bzoracler, is this a problem you've encountered in real code, or is this just a hypothetical? @picnixz, your argument in #129543 (comment) also doesn't make much sense to me in this case, however, I'm afraid :-) So I agree with @bzoracler that if we could go back in time and change it so that the default for the
Sure, I suppose. But again, I'm not really sure how much the inconsistency really matters in this case :-) |
@AlexWaygood, that particular snippet was artificial, but my issue was not that someone would use such a definition, but rather how to interpret a Changing the runtime default to Thanks all for the input - it seems like the consensus is "don't expect an explicit |
This is fixed on 3.14 for new-style TypeVars: the
It's not fixed for legacy (pre-PEP 695) TypeVars, but they're legacy for a reason. |
Bug report
Bug description:
I was trying to reconstruct typing interfaces in a
.pyi
stub file by using runtime symbols. When trying to extract the value of thebound=
argument totyping.TypeVar
, I came across this result (which to be fair is documented in the signature):In static type checkers, an omitted
bound=
is equivalent tobound=builtins.object
. The inconsistency with the runtime default value is problematic, because explicitly specifyingbound=None
also has a well-defined meaning to static type checkers (even if such a specification is rare):(mypy Playground, pyright Playground)
Not sure what the best course of action is here as any change to this will have backwards-compatibility concerns, but I think it's clear that static typing will not change an omitted
bound=
argument's interpretation tobound=None
, as that would break most existing typed code.CPython versions tested on:
3.9, 3.14
Operating systems tested on:
No response
The text was updated successfully, but these errors were encountered: