-
-
Notifications
You must be signed in to change notification settings - Fork 30.9k
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
Type expression is coerced to a list of parameter arguments in substitution of ParamSpec #88964
Comments
Type expression is coerced to a list of parameter arguments in substitution of ParamSpec. For example: >>> from typing import *
>>> T = TypeVar('T')
>>> P = ParamSpec('P')
>>> C = Callable[P, T]
>>> C[int, str]
typing.Callable[[int], str] int becomes [int]. There is even a dedicated test for this. But it is not followed from PEP-612. Furthermore, it contradicts one of examples in the PEP: >>> class X(Generic[T, P]):
... f: Callable[P, int]
... x: T
...
>>> X[int, int] # Should be rejected
__main__.X[int, int] It makes the implementation (at least the code in bpo-44796) more complex and makes the user code more errorprone. |
It's not, only the repr is like that. Internally it's not coerced. >>> C[int, str]
typing.Callable[[int], str]
>>> C[int, str].__args__
(<class 'int'>, <class 'str'>) Because Callable's correct form is Callable[[type], type] (where type is not ParamSpec or Concatenate) so the repr reflects that. Internally, Callable also flattens the list of args: >>> Callable[[int, str], int].__args__
(<class 'int'>, <class 'str'>, <class 'int'>) Because __args__ *must* be hashable and immutable. Otherwise, it will not work with Union or Literal. Some time ago we tried converting to nested tuple. But that was too difficult (and backwards incompatible) because every other typing operation expected __args__ to contain types, not a tuple. |
Thank you Ken Jin. So the problem is the __args__ (x, str) is interpreted differently depending on x, and after substituting x the interpretation can be changed. If x was ParamSpec, it was interpreted in one way, but if it becomes int, it is now interpreted in other way. The solution is to forbid substitution of P with wrong values (not parameters expression). Some normalization is also needed, before and after substitution. Other related example is: >>> from typing import *
>>> P = ParamSpec("P")
>>> class Z(Generic[P]): pass
...
>>> A = Z[[int]]
>>> B = Z[int]
>>> A
__main__.Z[(<class 'int'>,)]
>>> B
__main__.Z[int]
>>> A.__args__
((<class 'int'>,),)
>>> B.__args__
(<class 'int'>,) It is expected that A and B should the same. |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: