Python 3.9 includes PEP 585 and deprecates many of the types in the typing
module in favor of the ones in collections.abc
, now that they support __class_getitem__
. This is the case with for example Callable
. To me it would seem that typing.Callable
and collections.abc.Callable
should always behave similarly, but they do not.
This simple example results in an error:
>>> from typing import Optional
>>> from collections.abc import Callable
>>> def foo(arg: Optional[Callable[[int], int]]) -> None:
... pass
...
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "/usr/local/lib/python3.9/typing.py", line 262, in inner
return func(*args, **kwds)
File "/usr/local/lib/python3.9/typing.py", line 339, in __getitem__
return self._getitem(self, parameters)
File "/usr/local/lib/python3.9/typing.py", line 463, in Optional
return Union[arg, type(None)]
File "/usr/local/lib/python3.9/typing.py", line 262, in inner
return func(*args, **kwds)
File "/usr/local/lib/python3.9/typing.py", line 339, in __getitem__
return self._getitem(self, parameters)
File "/usr/local/lib/python3.9/typing.py", line 451, in Union
parameters = _remove_dups_flatten(parameters)
File "/usr/local/lib/python3.9/typing.py", line 231, in _remove_dups_flatten
return tuple(_deduplicate(params))
File "/usr/local/lib/python3.9/typing.py", line 205, in _deduplicate
all_params = set(params)
TypeError: unhashable type: 'list'
but the same error does not happen with typing.Callable
:
>>> from typing import Callable
>>> def foo(arg: Optional[Callable[[int], int]]) -> None:
... pass
...
>>> # no error
The error also doesn't happen if the signature is simplified a bit:
>>> from collections.abc import Callable
>>> def foo(arg: Optional[Callable[..., int]]) -> None:
... pass
...
>>> # no error
>>> def foo(arg: Callable[[int], int]) -> None:
... pass
...
>>> # no error
Is this a bug in Python 3.9 and 3.9.1?
Yes, collections.abc.Callable
doesn't work for typing purposes in 3.9.0 and 3.9.1. It was reported here and is fixed in 3.9.2 and 3.10. In the meantime you can continue to use typing.Callable
.