-
-
Notifications
You must be signed in to change notification settings - Fork 33.3k
Description
There is currently a difference in behaviour between collections.abc.Callable and typing.Callable for the following edge case involving ParamSpec substitution:
Running PGUpdate|x64 interpreter...
Python 3.12.0a6+ (heads/main:12226bec25, Mar 10 2023, 17:32:23) [MSC v.1932 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import typing as t, collections.abc as c
>>> P, T = t.ParamSpec("P"), t.TypeVar("T")
>>> t.Callable[P, T][[P, str], bool][int]
typing.Callable[[int, str], bool]
>>> c.Callable[P, T][[P, str], bool][int]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<frozen _collections_abc>", line 501, in __getitem__
File "<frozen _collections_abc>", line 456, in __new__
TypeError: Callable must be used as Callable[[arg, ...], result].According to PEP-612, this is an invalid substitution, for two reasons:
- Parameters can only be prepended to a
ParamSpecin a parameters list usingtyping(_extensions).Concatenate. - Appending parameters to a
ParamSpecin a parameters list is disallowed.
As such, the behaviour of collections.abc.Callable is more correct here, so ideally we'd change the behaviour of typing.Callable to match collections.abc.Callable.
However, this error should hopefully be caught by static type checkers anyway, and this is a false negative rather than a false positive. The runtime makes no promises that it will raise TypeError on all invalid substitutions, so fixing this should be low priority, in my opinion. We should first concentrate on fixing substitutions where the runtime raises exceptions, even though it shouldn't. For example:
This discrepancy in behaviour was first uncovered as part of a broader discussion in:
Cc. @sobolevn