是否有针对类型类型的规范“isinstance”实现?

Ane*_*pic 3 python-3.x mypy python-typing pydantic

您可以\xe2\x80\x99t 使用类型类型,例如Dict[str, int]在检查中isinstance

\n\n
Python 3.7.6 (default, Dec 30 2019, 19:38:28)\nType \'copyright\', \'credits\' or \'license\' for more information\nIPython 7.12.0 -- An enhanced Interactive Python. Type \'?\' for help.\n\nIn [1]: from typing import Dict\n\nIn [2]: myvar = {"a": 1}\n\nIn [3]: isinstance(myvar, Dict[str, int])\n---------------------------------------------------------------------------\nTypeError                                 Traceback (most recent call last)\n<ipython-input-3-a8fee57141ae> in <module>\n----> 1 isinstance(myvar, Dict[str, int])\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而,任何进行类型检查的库都需要能够执行类似的操作isinstance(myvar, Dict[str, int])(...我意识到它应该被称为与 不同的东西isinstance,这不是完全相同的事情)

\n\n

我觉得适用于打字的等效函数必须存在于某个地方,也许在mypy项目中?(但是里面\xe2\x80\x99s有很多复杂的代码,到目前为止我找不到\xe2\x80\x99)

\n\n

除了 mypy 之外,还有很多项目需要这个,例如像pydantic和 AFAICT 这样的库,它们都有复杂的手动实现,并且似乎有很多边缘情况(或者只是 \xe2\x80\xa6 \xe2\x80 \x98cases\xe2\x80\x99) 必须枚举和覆盖。这会导致错误/有限的类型识别,例如https://github.com/bloomberg/attrs-strict/issues/27

\n\n

似乎需要此功能的规范实现。是否已经存在于我尚未\xe2\x80\x99t 找到的地方?

\n\n

我给你一个来自 Python stdlib 的激励示例:

\n\n

https://docs.python.org/3/library/functools.html#functools.singledispatch

\n\n
\n

对于用类型注释的函数,装饰器将自动推断第一个参数的类型:

\n
\n\n
>>> @fun.register\n... def _(arg: int, verbose=False):\n...     if verbose:\n...         print("Strength in numbers, eh?", end=" ")\n...     print(arg)\n...\n>>> @fun.register\n... def _(arg: list, verbose=False):\n...     if verbose:\n...         print("Enumerate this:")\n...     for i, elem in enumerate(arg):\n...         print(i, elem)\n
Run Code Online (Sandbox Code Playgroud)\n\n

嗯,这很酷。但这是作弊,因为现在我们通常不会使用list内置函数来注释第二个函数,而是使用诸如List[str]...之类的东西,但这不起作用,因为singledispatch只是做了一个幼稚的isinstance检查,这可以\不处理泛型类型。因此singledispatch并不像它声称的那样真正支持通过类型注释进行调度。

\n

SCo*_*vin 6

不,没有此类规范检查。正如评论者所说,类型是为了静态类型检查而引入的,我认为许多核心开发人员认为它应该保持这样。

我能想到的最接近的是 pydantic 的parse_obj_as。它的不同之处在于它尝试将对象强制转换为特定类型,如果失败则会引发错误,但它非常接近。

用法:

from pydantic import parse_obj_as
from typing import Dict

parse_obj_as(Dict[str, int], {'xxx': 1, 'yyy': 2})
#> {'xxx': 1, 'yyy': 2}

parse_obj_as(Dict[str, int], {'xxx': 1, 123: '12'})
#> {'xxx': 1, '123': 12}

parse_obj_as(Dict[str, int], ['not a dict'])
#> ValidationError: 1 validation error for ParsingModel[Dict[str, int]]
#> __root__
#>   value is not a valid dict (type=type_error.dict)
Run Code Online (Sandbox Code Playgroud)

文档在这里

注意:我构建了 pydantic,所以我有点偏见。