【问题标题】:Is there a canonical “isinstance” implementation for typing types?输入类型是否有规范的“isinstance”实现?
【发布时间】:2020-07-14 06:04:05
【问题描述】:

您不能在isinstance 检查中使用typing 之类的Dict[str, int] 类型:

Python 3.7.6 (default, Dec 30 2019, 19:38:28)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.12.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: from typing import Dict

In [2]: myvar = {"a": 1}

In [3]: isinstance(myvar, Dict[str, int])
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-3-a8fee57141ae> in <module>
----> 1 isinstance(myvar, Dict[str, int])

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

我觉得打字的等效功能必须存在于某个地方,也许在mypy项目中? (但是里面有很多复杂的代码,我暂时没找到)

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

似乎需要对这个功能进行规范的实现。是否已经存在于我没有找到的某个地方?

我给你一个来自 Python 标准库的激励示例:

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

对于带有类型注解的函数,装饰器会自动推断第一个参数的类型:

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

嗯,这很酷。但这是作弊,因为这些天我们通常不会使用 list 内置注释第二个函数,而是使用 List[str]... 之类的东西,这是行不通的,因为 singledispatch 只是在做一个幼稚的 @987654337 @检查,这无法处理键入泛型。所以singledispatch 并不像它声称的那样真正支持通过类型注释进行调度。

【问题讨论】:

  • mypy 是关于静态检查的。整个typing 系统确实面向静态检查——运行时自省似乎是事后才想到的。即使是像typing.get_args 这样的东西,你希望从第一天就开始使用,直到 Python 3.8 被引入。那是在typing 本身进入 Python 3.5 之后的 4 年多。
  • @Georgy 有点,是的,因为似乎没有好的答案,只是很多人都在为缺乏对核心typing 库中这种检查的支持而苦苦挣扎。这是另一个相关问题,有一些很好的答案stackoverflow.com/questions/50563546/…

标签: python-3.x mypy python-typing pydantic


【解决方案1】:

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

我能想到的最接近的是 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)

文档here.

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

【讨论】:

  • 感谢您的回答,也感谢 Pydantic - 这个库太棒了! (我似乎在我最近做的每个项目中都发现了它的用途......)这使得 Pydantic 的方法非常清楚,我将其解释为务实的 EAFP(“尝试实例化为”)而不是严格的验证。跨度>
猜你喜欢
  • 2015-09-22
  • 2014-06-09
  • 1970-01-01
  • 2016-09-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-22
  • 2023-01-10
  • 1970-01-01
相关资源
最近更新 更多