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 感谢您的尝试。我实际上尝试通过gitter
与mypy
人取得联系,似乎有一个类似的功能正在开发中,我会看看我是否可以从项目中找人来回答,也许会在它移动时更新它前进。
据我了解,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"
【讨论】:
是的。在回答类似问题时,我也得出了这个结论(尽管我删除了这些段落,因为我认为我的解释不是很清楚)。我认为 pythontyping
/ 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 中运行 Sanic 应用程序的未定义符号
当我在 mac 上安装了 python 3.5 时,终端运行 python 2.7。