issubclass(typing.List, list) 引发 TypeError
issubclass(typing.List, list) raises TypeError
typing.List
在 docs 中被定义为 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__)
(因为参数 cls
是 list
而这不是 _GenericAlias
的实例).因此它又是与 issubclass(list, list)
.
相同的结果
使用 issubclass(typing.List, list)
调用 list
的 __subclasscheck__
方法(该调用等同于 list.__subclasscheck__(typing.List)
)。
现在失败了,因为 subclass-checks 需要两个参数,它们是 classes,而不是实例。但是 typing.List
是 _GenericAlias
的实例而不是 class。所以这失败了 TypeError
.
typing.List
在 docs 中被定义为 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 asclass 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__)
(因为参数 cls
是 list
而这不是 _GenericAlias
的实例).因此它又是与 issubclass(list, list)
.
使用 issubclass(typing.List, list)
调用 list
的 __subclasscheck__
方法(该调用等同于 list.__subclasscheck__(typing.List)
)。
现在失败了,因为 subclass-checks 需要两个参数,它们是 classes,而不是实例。但是 typing.List
是 _GenericAlias
的实例而不是 class。所以这失败了 TypeError
.