静态类型化Python 3的一个子集
项目描述
Nope是一个可以编译到多个目标的Python 3的静态类型子集。目前,只支持Python和node.js。任何有效的Nope程序都可以直接作为Python 3程序运行。
支持静态类型化的主要原因有两个
静态类型化可以更快地检测一些编程错误
静态类型化允许对生成的代码进行优化
由于以下原因,静态类型是用注释而不是注解来表达的
这意味着静态类型在运行时没有效果,允许Nope程序直接作为Python 3程序运行,而不需要任何额外的依赖或性能损失。
可以在注释中使用单独的语法来简洁地表达类型,而不是(滥用)现有的Python语法。
将函数的签名与其实现解耦可能很有用。例如,使用单独的注释可以轻松地为函数指定仅按位置接受参数而不是关键字。
以下是一个使用Nope计算斐波那契数的示例
#:: int -> int
def fib(n):
seq = [0, 1]
for i in range(2, n + 1):
seq.append(seq[i - 1] + seq[i - 2])
return seq[n]
print(fib(10))
待办事项
在定义类中的__add__和类似方法时,类型签名应该具体,例如在int上,为int → int。然而,为了与Python保持兼容,类型检查器在检查实际方法时应该假设参数是顶级类型,因此仍然需要使用isinstance或类似的函数。
支持操作符的r版本,例如__radd__。
继承
初始化方法__init__
标准库支持
根据平台指定依赖项的方法,以便将现有库模拟为通用接口。
允许以与函数相同的方式指定变量的类型,例如给出空列表的类型。
如果一个类的定义体包含一个可能是函数(但在运行时无法确定)的对象类型值,应该如何处理?在Python中,如果它是一个函数,我们将它绑定到实例。在其他语言中是否可以合理地做到同样的效果?结果是,任何对象类型的值都需要检查它是否是函数,以确保一致性。
内置函数的正确测试
防止函数和类的重新定义
允许互递归函数
确保所有签名都用于类型规则中
状态
语法
本节描述了对解析和类型检查Python 3.4的每个语法节点的支持。请注意,并非所有后端都支持所有功能。
函数定义:部分支持。
name:支持。
arguments:部分支持。位置参数和关键字参数支持,但不支持其他内容(默认值、*args、**kwargs、关键字只参数)。
body:支持。
decorators:不支持。
annotations:不支持(既不支持参数也不支持返回注释)。
函数的签名应通过函数定义之前的签名注释指定。例如
#:: int -> int def increment(x): return x + 1 #:: int, str -> none def repeated_greeting(repeat, message): for i in range(0, repeat): print(message) #:: repeat: int, message: str -> none def repeated_greeting(repeat, message): for i in range(0, repeat): print(message)
类定义:不支持。
返回语句:支持。
删除语句:不支持。
赋值:部分支持。对变量(例如x)、序列元素(例如x[i])和属性(例如x.y)的赋值支持,但不支持对切片的赋值(例如x[:])。
增强赋值:不支持。
for 循环:支持。
while 循环:支持。
if 语句:支持。
with 语句:支持。
raise 语句:部分支持。仅支持形式为raise value的语句。不支持raise、raise ExceptionType和raise value1 from value2。
try 语句:部分支持。当在异常处理程序中指定类型时,不支持异常的元组。忽略else分支。
assert 语句:支持。
导入语句:部分支持。支持导入语句的各种形式。然而,目前只支持本地模块。标准库模块或依赖项不支持。
global 关键字:不支持。
nonlocal 关键字:不支持。
表达式语句:支持。
pass 关键字:支持。
break 关键字:支持。
continue 关键字:支持。
With 语句
考虑以下内容
with x:
y = f()
g(y)
不能保证y已被赋值,因为f()可能会引发异常,然后被上下文管理器的__exit__方法抑制。因此,g(y)无法通过类型检查。(如果异常没有被__exit__方法抑制,我们可以安全地假设变量已被赋值,因为我们不会在异常后执行任何代码)。然而,在常见情况下,我们希望能够假设变量已被赋值,这种假设在许多情况下都是安全的,例如
with open(path) as file_:
contents = file_.read()
print(contents)
我们可以通过检查__exit__的类型来允许这样的示例通过类型检查。如果其返回类型是none,则它保证返回一个假值,这意味着它永远不会抑制异常。
Python
任何有效的Nope程序都应直接使用Python 3.4执行。支持Python 3.4之前版本的最好方法是,与正常Python 3.4代码库相同,即避免使用早期版本不支持的功能。
Node.js后端
支持的内建函数
abs:支持
bool:部分支持。魔法方法__bool__被忽略。
iter:部分支持。序列协议不受支持。
print:只接受单个参数。
未实现的优化
如果布尔操作(“and”或“or”)的结果仅用作条件,例如“if”语句或“while”循环的条件,那么值可以是真或假,而不是操作的实际值。换句话说,x and y可以优化为bool(x) && bool(y)。
除非显式调用bool(),否则布尔值、字符串和整数可以直接使用,如果仅用于它们的真值,例如在if语句条件中。
避免在条件中使用直接布尔操作时重新评估bool(value)。例如,在if x and y中,bool(x)只需评估一次,即使bool(x)是True。(一个简单的实现会为and操作评估一次bool(x),其值为x,导致再次评估bool(x)作为if语句的条件。)
与Python 3的区别
内建的子类化
Nope不允许某些内建函数的子类化,如int和list。这种限制意味着类型为int的值保证具有具体的类型int而不是int的子类,允许在生成代码时使用某些优化。