Python 3.9.1 中的 collections.abc.Callable 是否有 bug?

ruo*_*ola 9 python python-3.x python-collections python-typing python-3.9

Python 3.9包括PEP 585并弃用了模块中的许多类型,typing转而支持 中的类型collections.abc,现在它们支持__class_getitem__. 例如,就是这种情况Callable。对我来说,似乎typing.Callablecollections.abc.Callable应该总是表现得相似,但事实并非如此。

这个简单的示例会导致错误:

>>> 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'
Run Code Online (Sandbox Code Playgroud)

但同样的错误不会发生typing.Callable

>>> from typing import Callable
>>> def foo(arg: Optional[Callable[[int], int]]) -> None:
...    pass
...
>>> # no error
Run Code Online (Sandbox Code Playgroud)

如果签名稍微简化一下,也不会发生该错误:

>>> 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
Run Code Online (Sandbox Code Playgroud)

这是 Python 3.9 和 3.9.1 中的错误吗?

jon*_*rpe 6

是的,collections.abc.Callable在 3.9.0 和 3.9.1 中不适用于打字目的。已在此处报告并在3.9.2和 3.10中修复。在此期间您可以继续使用typing.Callable