typing.Mapping 等可以在 3.7 及更高版本中与 functools.singledispatch 一起使用吗?

Can typing.Mapping and such be used with functools.singledispatch in 3.7 and up?

升级到 3.7 版后,我有一个使用 functools.singledispatch with generics 中断的功能。过去在 3.6 中工作的内容:

>>> from functools import singledispatch                             
>>> from typing import Mapping                                   
>>> @singledispatch                                 
... def f(_):                               
...  raise NotImplementedError
... 
>>> @f.register(Mapping)
... def _(x):
...  return x
... 

现在加注

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/user/cpython/Lib/functools.py", line 831, in register
    raise TypeError(
TypeError: Invalid first argument to `register()`: typing.Mapping. Use either `@register(some_class)` or plain `@register` on an annotated function.

注册带注释的版本也好不到哪儿去:

>>> @f.register
... def _(x: Mapping):
...  return x
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "/home/user/cpython/Lib/functools.py", line 842, in register
    raise TypeError(
TypeError: Invalid annotation for 'x'. typing.Mapping is not a class.

我之前是否一直在滥用单一分派和泛型,有没有办法在 3.7 及更高版本中实现等效行为?

您需要 collections.abc.Mapping。通用 classes 大多与任何类型的运行时检查都不兼容。

几乎没有存在的兼容性大多没有记录并且经常更改。例如,typing.Mapping 曾经是一个 class,文档仍然 它是一个 class,但它现在真的只是假装是一个. functools.singledispatch 需要一个真正的 class.