issubclass(typing.List, list) 引发 TypeError

issubclass(typing.List, list) raises TypeError

typing.Listdocs 中被定义为 class typing.List(list, MutableSequence[T]),这应该意味着它是 list 的子 class,但是 issubclass()似乎对此感到困惑:

issubclass(typing.List, typing.List) returns 正确,确认 typing.List 是 class.

But issubclass(typing.List, list) raises TypeError: issubclass() arg 1 must be a class, 表示相反!

为了完成混淆,issubclass(list, typing.List) returns 正确

我知道我误解的可能性远大于核心库函数被破坏的可能性,但我很想知道原因!

这是Python3.8.7

typing.List is defined as class typing.List(list, MutableSequence[T])

是也不是。我认为这更应该描述行为,但它不是以这种方式实现的。

查看 cpython 源代码如何 List is defined. It's an instance of _GenericAlias
如果您使用 type():

也可以找到它
>>> type(typing.List)
<class 'typing._GenericAlias'>

您可以看到 class 已经实现了 magic method __subclasscheck__。为了进一步参考,我 copied/cite 来自 cpython 存储库的这些行:

def __subclasscheck__(self, cls):
    if self._special:
        if not isinstance(cls, _GenericAlias):
            return issubclass(cls, self.__origin__)
        if cls._special:
            return issubclass(cls.__origin__, self.__origin__)
    raise TypeError("Subscripted generics cannot be used with"
                    " class and instance checks")

当你现在调用issubclass(typing.List, typing.List)时,python调用这个方法,因为两个参数都是_GenericAlias和特殊(._special = True)的实例,这个方法将进入这个分支:return issubclass(cls.__origin__, self.__origin__)
self__origin__ 是内置类型 list。 所以调用 issubclass(typing.List, typing.List) 最后就是调用 issubclass(list, list)。这意味着您检查的不是真正的 typing.List ifself,而是表示的内置类型。

当您调用 issubclass(typing.List, list) 时,将进入分支 return issubclass(cls, self.__origin__)(因为参数 clslist 而这不是 _GenericAlias 的实例).因此它又是与 issubclass(list, list).

相同的结果

使用 issubclass(typing.List, list) 调用 list__subclasscheck__ 方法(该调用等同于 list.__subclasscheck__(typing.List))。
现在失败了,因为 subclass-checks 需要两个参数,它们是 classes,而不是实例。但是 typing.List_GenericAlias 的实例而不是 class。所以这失败了 TypeError.