为什么 Python 不允许使用 isinstance 检查泛型?

问题描述 投票:0回答:1

使用 Python 3.12.4 运行以下代码:

from typing import Generic, TypeVar

T = TypeVar("T")

class Foo(Generic[T]):
    def some_method(self) -> T:
        pass

isinstance(Foo[int](), Foo[int])

它会抛出一个

TypeError: Subscripted generics cannot be used with class and instance checks

Traceback (most recent call last):
  File "/path/to/a.py", line 9, in <module>
    isinstance(Foo[int](), Foo[int])
  File "/path/to/.pyenv/versions/3.12.4/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 1213, in __instancecheck__
    return self.__subclasscheck__(type(obj))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/path/to/.pyenv/versions/3.12.4/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/typing.py", line 1216, in __subclasscheck__
    raise TypeError("Subscripted generics cannot be used with"
TypeError: Subscripted generics cannot be used with class and instance checks

Python 不允许

isinstance
检查
Generic
s 的理由是什么?

python generics python-typing isinstance
1个回答
0
投票

在运行时,类型参数不可验证。这种关系仅在类型检查时检查:

请注意,[作为示例给出的变量]的运行时类型(类)仍然只是

Node
Node[int]
Node[str]
是可区分的类对象,但通过实例化它们创建的对象的运行时类并不相同记录区别。这种行为称为“类型擦除”;这是具有泛型的语言(例如 Java、TypeScript)中的常见做法。

泛型 - Python 类型系统规范

例如,如果

isinstance(..., list[str])
要在
isintansce(..., list)
处处理,结果会非常混乱:

>>> a = [1, 2, 3]
>>> isinstance(a, list[str])
True

还要考虑类型参数不具体的情况:

def is_list_of(v: Any, element_type: type[T]) -> None:
    isinstance(v, list[T])  # ???

自 PEP 484 以来,情况一直如此,尽管不是很明确(CallableGenerics 是两个不同的部分,并且此注释的含义似乎与我们所理解的略有不同)是,尽管概念上是相同的):

[...]

isinstance(x, typing.Callable[...])

 不支持。

但是,有一些运行时类型检查器可以完成这种繁重的工作,例如 Pydantic。

历史上,PEP 484 通知是在

此提交中添加的,并且与类型擦除相关的问题在此 GitHub 问题中讨论。由于性能问题,GvR 和其他贡献者似乎最初反对 Node[int]()

(随后它在运行时工作,但速度非常慢,并且被 Mypy 禁止)。

© www.soinside.com 2019 - 2024. All rights reserved.