Python >=3.5:在运行时检查类型注释

Posted

技术标签:

【中文标题】Python >=3.5:在运行时检查类型注释【英文标题】:Python >=3.5: Checking type annotation at runtime 【发布时间】:2017-09-24 14:26:45 【问题描述】:

typing 模块(或任何其他模块)是否具有在运行时对变量进行类型检查的 API,类似于 isinstance() 但了解 typing 中定义的类型类?

我想从事类似的工作:

from typing import List
assert isinstance([1, 'bob'], List[int]), 'Wrong type'

【问题讨论】:

不,你不能,但这里有一个类似的问题:***.com/questions/37973820/…,我试图回答它。 @max 感谢您的尝试。我实际上尝试通过gittermypy 人取得联系,似乎有一个类似的功能正在开发中,我会看看我是否可以从项目中找人来回答,也许会在它移动时更新它前进。 据我了解,typing_inspect 并不是您想要的;更多的是检查类型对象本身。 在这个密切相关的问题中有一个非常精细的类型检查实现:Validating detailed types in python dataclasses 谢谢你,似乎答案中有足够的代码来保证一个小(但非常有用)的包;) 【参考方案1】:

我在寻找类似的东西并找到了库typeguard。这可以在您想要的任何地方自动进行运行时类型检查。还支持直接在问题中检查类型。从文档中,

from typeguard import check_type

# Raises TypeError if there's a problem
check_type('variablename', [1234], List[int])

【讨论】:

更好的是,typeguard 的@typechecked 装饰器让您可以自动对函数的所有输入和输出进行类型提示验证。或者,如果你把它放在一个类定义上,它会对它的所有方法进行运行时验证【参考方案2】:

typing 模块中没有这样的功能,而且很可能永远不会有。

检查一个对象是否是一个类的实例——这只意味着“这个对象是由该类的构造函数创建的”——只是测试一些标记的简单问题。

然而,检查一个对象是否是一个类型的“实例”并不一定是可判定的:

assert isinstance(foo, Callable[[int], str]), 'Wrong type'

虽然很容易检查foo 的输入注释(假设它不是lambda),但根据赖斯定理,检查它是否符合它们通常是不确定的。

即使使用更简单的类型,例如List[int],测试也很容易变得非常低效,无法用于除了最小的玩具示例之外的任何内容。

xs = set(range(10000))
xs.add("a")
xs.pop()
assert isinstance(xs, Set[int]), 'Wrong type'

允许类型检查器以相对有效的方式执行此操作的技巧是保守:类型检查器试图证明foo 总是返回int。如果失败,它会拒绝程序,即使程序可能是有效的,即这个函数很可能会被拒绝,尽管它是完全安全的:

def foo() -> int:
    if "a".startswith("a"):
        return 1
    return "x"

【讨论】:

是的。在回答类似问题时,我也得出了这个结论(尽管我删除了这些段落,因为我认为我的解释不是很清楚)。我认为 python typing / PEP 484 类型系统是为静态类型检查而构建的,不适合动态类型检查。 可以构建一个实际有用的动态类型系统,但它与PEP 484 有很大不同(主要是简单得多)。可以说,您的现成 python 解释器中已经包含了一个相当不错的解释器。 “打字模块中没有这样的功能,而且很可能永远不会有。” -- 哎呀! @Elazar:很好的答案!有点吹毛求疵:我认为赖斯定理不足以证明类型系统是不可判定的。决定一个类型系统是否是可判定的并不是那么容易。 :-) 3fx.ch/typing-is-hard.html (我不知道 Python 是否有一个定义明确的类型系统,它具有某种参数多态性。如果有,它可能是无法确定的。但证明它可能是大量的工作.)【参考方案3】:

这是我最近发现的,基本上这个装饰器会在运行时进行类型检查,如果某些类型定义不匹配,则会引发异常。它还可以对嵌套类型(字符串字典等)进行类型检查

https://github.com/FelixTheC/strongtyping

例子:

from strongtyping.strong_typing import match_typing

@match_typing
def func_a(a: str, b: int, c: list):
   ...

func_a('1', 2, [i for i in range(5)])
# >>> True

func_a(1, 2, [i for i in range(5)])
# >>> will raise a TypeMismatch Exception

【讨论】:

以上是关于Python >=3.5:在运行时检查类型注释的主要内容,如果未能解决你的问题,请参考以下文章

Python 3.5 类型注解

尝试在 Python 3.5 中运行 Sanic 应用程序的未定义符号

当我在 mac 上安装了 python 3.5 时,终端运行 python 2.7。

RuntimeError:安装 python 库时需要 Python 版本 >= 3.5

Day1 - Python基础1 介绍基本语法流程控制

python赋值问题