40

我正在使用现有的大型 Python 代码库,并希望开始添加类型注释,以便进行某种程度的静态检查。我在想像ErlangStrongtalkTyped Scheme/Racket之类的东西。

我见过快速而肮脏的装饰器,它们根据函数参数和返回类型注释插入动态检查,但我正在寻找更健壮并在编译时执行检查的东西。

现在有哪些工具可用于此类事情?我熟悉编译器和类型检查,如果它有良好的基础,我肯定愿意改进一个不完整的工具。

(注意:我对讨论静态类型的优缺点不感兴趣。)

编辑:一个例子:

def put(d, k, v):
   d[k] = v

我希望能够将该put函数注释为具有 type put<K,V>(dict<K,V>, K, V) -> None

更新:新的PEP 484(2014 年 9 月)定义了 Python 3.5+ 中静态类型和类型注释的标准。有一个名为mypy的类型检查工具与 PEP 484 兼容。

4

7 回答 7

17

编辑 2016-11-11:只需使用mypy。可以逐渐添加类型提示。在 Python 3 源代码中,它验证标准PEP 484类型提示。类型仍然可以在 Python 2 中使用特殊注释来表示。圭多喜欢它

这篇文章最初是很久以前在 mypy 出现之前写的。我在下面保留了帖子的原始内容,尽管它不是很准确。


原帖:

您可能想查看有关 Python 静态分析的相关 StackOverflow 帖子中提到的一些项目。

总之:

由于 Python 广泛使用鸭子类型,在其他语言中可能被称为“类型错误”的事情最终可能在 Python 中成为“对象X不支持方法Y ”。

编辑 2011-05-17:

我同意 delnan 的观点,即 Python [显然错误]不可能进行静态类型化。但是由于我们的怀疑似乎并没有阻止你,我只能给你更多关于这个主题的信息。有请:

  • Python 类型推断的讨论。(其他链接来自这里。)
  • Guido van van Rossum 关于添加可选静态类型的文章:第 1部分和第 2 部分
  • RPython是 Python 的一个子集,它可能有机会被静态分析到足以进行某种形式的类型检查。
于 2011-05-17T02:50:27.440 回答
11

你可能会觉得mypy很有趣。Guido已提议将其包含在 Python 3.5 中。

于 2014-09-07T21:35:06.973 回答
6

查看这篇文章:PySonar:Python 的静态分析器。PySonar 是一种使用代码的抽象解释(部分执行)来推断类型的工具。它找到程序的所有可能执行路径,并找到所有变量的所有可能类型。

PySonar 基本上有三个版本:

  • 开源 Java(Jython 索引器)
  • 闭源 Java(隐藏在 Google 中)
  • 开源 Python ( mini-pysonar )

它们中的任何一个(除了封闭源代码之外)都没有完全实现。但基本的想法是你可以把它作为你工作的基础。

于 2013-07-01T09:39:09.000 回答
3

我不知道这是否有帮助,但为了它的价值,科罗拉多大学的 Jeremy Siek 做了一些渐进式打字的工作,我发现这是在快速搜索。 http://www.wiki.jvmlangsummit.com/pdf/28_Siek_gradual.pdf

我的猜测(我可能错了)是目前你找不到任何有前途的开源工具,因为他的研究看起来相对较新。

您最好的选择可能是联系作者并询问他们是否可以向您发布他们的代码。

于 2011-06-15T18:05:23.127 回答
2

我喜欢prospectorlandscape.io的后端。它将现有分析器的输出(例如 pylint、pyflakes、pep8、frosted...)合并到一份报告中。整洁的。

于 2014-08-26T14:21:35.893 回答
2

Python 3 有“渐进式”包;请参阅PIPBitbucket 存储库

显然,这是由Jeremy Siek周围的小组实施的,他似乎是渐进式打字领域的权威。

一些注释显然是必要的,这里是一个例子:

from gradual import *

@typed
def calculate_total(a:int, b:int) -> int:
    return a + b//100

就注释而言,这还不错。我没有使用过这个包,所以我不能谈论它的质量,但是它的语法(以及它背后的人)确实让它看起来很有前途。

于 2013-11-13T07:27:17.193 回答
1

前段时间我也有类似的需求。我发现的所有现有解决方案都有一些问题或没有我想要的功能,所以我自己做了。

以下是你如何使用它:

from requiretype import require

@require(name=str, age=(int, float, long))
def greet_person(name, age):
    print "Hello {0} ({1})".format(name, age)

>>> greet_person("John", 42)
Hello John (42)

>>> greet_person("John", "Doe")
# [...traceback...]
TypeError: Doe is not a valid type.
Valid types: <type 'int'>, <type 'float'>, <type 'long'>

>>> greet_person(42, 43)
# [...traceback...]
TypeError: 42 is not a <type 'str'> type

我希望这对你有用。

有关更多详细信息,请查看:

PS:(从github repo引用我自己)

在大多数情况下,我建议使用测试而不是类型检查,因为在 Python 中这样做更自然。但是,在某些情况下,您希望/需要指定要使用的特定类型,并且由于 python 没有对参数的类型检查,因此这很有用。

于 2015-10-29T00:47:10.803 回答