代码之家  ›  专栏  ›  技术社区  ›  Theo d'Or

为什么不推断所有静态类型?

  •  1
  • Theo d'Or  · 技术社区  · 6 年前

    由于Python支持类型注释,因此它支持静态类型规则。使用由生成的AST时 ast 模块时,我突然想到,给定这样的规则,所有类型都可以推断,不需要类型注释。给定一个静态类型pragma(可能是代码文件顶部的注释),解析器中的附加逻辑层可以遍历AST以确定所有变量的类型。

    例如,从 Mypy website :

    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
    

    格言 d 它的键和值是用注释键入的,但是可以从下面的循环中推断出类型: s 是一个 str f ,从文件中读取的内容;并且dict项值是一个 int 因为这就是赋值表达式返回的结果。

    对于静态类型来说,执行这样的代码分析通常过于昂贵而无法推断,还是我遗漏了其他东西?

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

    1 回复  |  直到 6 年前
        1
  •  1
  •   Dunes    6 年前

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

    ** 接线员( int.__pow__ )返回一个 int A. float ,或 complex 取决于类型 它的操作数。如。

    >>> 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 (二)共同基础 int 浮动 ),这可能不是所希望的。通过给变量一个类型注释,我们可以使mypy在分配给变量时进行类型检查 Z x ** y ,但任何未来的行动 Z 可以安全地假定 Z 无论它被定义为什么。