【问题标题】:Why is all static typing not inferred?为什么不推断所有静态类型?
【发布时间】:2019-06-06 10:19:12
【问题描述】:

由于 Python 支持类型注释,它启用了静态类型规则。在使用 ast 模块生成的 AST 时,我感到震惊的是,鉴于这样的纪律,所有类型都可以推断出来,应该不需要类型注释。给定一个静态类型杂注(可能是代码文件顶部的注释),解析器中的附加逻辑层可以遍历 AST 以确定所有变量的类型。

例如,从Mypy website中获取这段代码的sn-p:

d = {}  # type: Dict[str, int]

with open(sys.argv[1]) as f:
    for s in f:
        for word in re.sub('\W', ' ', s).split():
            d[word] = d.get(word, 0) + 1

dict d 及其键和值是用注释键入的,但可以从以下循环中推断出类型:sstr 如果它在 f 中,则内容为从文件中;并且 dict 项的值是 int,因为这是赋值表达式返回的内容。

是不是对代码执行这种分析通常过于昂贵而无法推断出静态类型,还是我错过了其他东西?

请注意,这个问题与关于动态与静态类型或可选类型的讨论无关。我的观点是关于当程序员同意静态类型时的类型推断。

【问题讨论】:

  • 这里有一个难题:在代码x = eval(input("Enter any value:"))中,x的类型是什么?
  • @Kevin 可能是包装eval 可能产生的所有其他类型的 EvalOutput 对象。我的意思是,有志者事竟成。以零讨论所呈现的主题来吸引人们对这种极端情况的关注,这真的有帮助吗?从那以后,我了解到我的问题所指的是“结构化类型”而不是“名义上的”。所以这个想法并不新鲜,这个问题也不是不合理的。特别是在 Python 这样的语言环境中,考虑到迄今为止该语言的使用方式,用户可能喜欢在没有注释的情况下进行静态类型是可以理解的。
  • 我认为这也是一个合理的问题 :-) eval 在生产质量代码中非常罕见,如果我们忽略包含 eval 或声明的程序,是否可以进行静态类型分析仍然值得询问它返回一个 EvalOutput 或其他。我之前的评论旨在发人深省,而不是讨论结束。另一个开放式问题:类型分析器应该如何处理y = random.choice([1, "foo"])

标签: python parsing abstract-syntax-tree static-typing inferred-type


【解决方案1】:

问题是类型注释是可选的。事实上,re 模块没有类型注释,即使在 Python 3.8 中也没有。当然,分析器可以内省 Python 代码以查看发生了什么。但是,对于某些代码(如re 模块),代码最终会进入 C-API(在 CPYthon 中)。此时分析器无法确定函数的类型签名是什么。作为人类,我们可以阅读文档并知道 re.sub 总是返回一个 str 的实例,但是自动化工具无法知道,除非它们提供了补充类型信息。

那么你有一些函数返回类型联合的问题。例如。 ** 运算符 (int.__pow__) 返回 intfloatcomplex,具体取决于其操作数的类型和值。例如。

>>> 3 ** 2
9
>>> 3 ** -2
0.1111111111111111
>>> 2 ** 0.5
1.4142135623730951
>>> (-1) ** 0.5
(6.123233995736766e-17+1j) # should really just be 1j

这意味着,给定:

def f(x: int, y: int):
   z = x ** y

z 将被分配 object 的类型(intfloatcomplex 的公共基数),这可能不是我们想要的。通过给变量一个类型注解,我们可以让 mypy 在将x ** y 的结果分配给z 时进行类型检查,但是以后对z 的任何操作都可以安全地假定z 的类型是任意的它被定义为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多