RPython中的静态类型是什么?

14 投票
2 回答
1795 浏览
提问于 2025-04-17 00:11

人们常常说 RPython(Python的一种子集)是静态类型的。(比如在维基百科上。)

一开始,我在想他们是怎么把这个特性加到Python里的,觉得可能是要求在每个函数的开头加上像 assert isinstance(arg1, ...) 这样的语句(但我真的不太相信这个)。

然后我看了一些RPython的代码,发现它看起来根本不像是静态类型的。在很多情况下,编译器可能能证明一个函数的参数只能是某几种类型,但并不是所有情况下都能做到。

比如,这就是 string.split 的RPython实现:

def split(value, by, maxsplit=-1):
    bylen = len(by)
    if bylen == 0:
        raise ValueError("empty separator")

    res = []
    start = 0
    while maxsplit != 0:
        next = value.find(by, start)
        if next < 0:
            break
        res.append(value[start:next])
        start = next + bylen
        maxsplit -= 1   # NB. if it's already < 0, it stays < 0

    res.append(value[start:len(value)])
    return res

在关于RPython的PyPy文档中提到:“变量应该只包含一种类型的值”。

那么,函数参数也算是变量吗?或者说RPython到底是怎么静态类型的?这是不是说错了呢?

2 个回答

4

是的,它是静态类型的。在你的例子中,所有的变量类型都没有改变,这符合RPython的要求。RPython并没有一个正式的定义,它的限制也在不断变化,不过文档还是一个很好的入门资料。在稍微了解一下之后,最好的办法就是尝试翻译一些代码,你会很快明白哪些可以做,哪些不可以做!

16

那么,函数的参数也算变量吗?

当然算。在几乎所有编程语言中,都是这样。

那RPython到底是以什么方式静态类型的?或者说这其实是说错了?

这个说法是对的。RPython不是Python。 它是Python的一个子集,可以作为Python代码运行。但是,当你真正编译RPython代码时,很多动态特性就被去掉了(不过这只是在导入之后,所以你仍然可以使用类元、从字符串生成代码等,这在某些模块中效果很好),这样编译器(这不是 Python编译器,而是与传统编译器有很大不同的编译器;具体可以查看相关文档)就能确定类型是静态的。更准确地说,使用动态特性的代码可以通过解析器,但最终会在某个时刻导致类型错误。

在很多情况下,编译器可能能证明一个函数参数只能是某些特定类型,但并不是所有情况下都是这样。

当然不是。很多代码并不是静态类型的,还有一些静态类型的代码当前的注释工具无法证明是静态类型的。但是当遇到这样的代码时,就会出现编译错误,没得说。

有几个重要的点需要了解:

  • 类型是推断出来的,而不是明确写出来的(大部分情况下是这样;我相信有一些函数需要断言来帮助注释工具)。静态类型并不意味着类型必须写出来(那叫显式类型),而是每个表达式(包括变量)都有一个单一的类型,这个类型是不会改变的。

  • 所有的分析都是在整个程序的基础上进行的!你不能为一个函数 def add(a, b): return a + b 推断出一个(非泛型)类型(因为参数可能是整数、浮点数、字符串、列表等等),但是如果这个函数用整数参数调用(比如整数字面量或之前被推断为包含整数的变量),那么就可以确定 ab(以及由于 + 的类型,add 的结果)也是整数。

  • PyPy库中的所有代码都不是RPython。例如,有一些代码生成器(比如在 rlib.parsing 中)是在编译时运行并生成RPython代码,但它们本身并不是RPython(顺便提一下,通常会有一个 "NOT_RPYTHON" 的文档字符串)。此外,标准库的大部分是用完整的Python编写的(大多直接取自CPython)。

关于整个翻译和类型系统是如何工作的,有很多非常有趣的资料。例如,RPython工具链描述了翻译过程,包括类型推断,而RPython类型系统则描述了使用的类型系统。

撰写回答