我建议阅读PEP 483 https://www.python.org/dev/peps/pep-0483/ and PEP 484 https://www.python.org/dev/peps/pep-0484/并观看这个演示文稿 https://www.youtube.com/watch?v=2wDvzy6Hgxg by Guido https://en.wikipedia.org/wiki/Guido_van_Rossum关于类型提示。
简而言之: 类型提示就是字面上的意思。您暗示您正在使用的对象的类型.
因为dynamicPython 的本质,推断或检查类型正在使用的物体尤其困难。这一事实使得开发人员很难理解他们尚未编写的代码中到底发生了什么,最重要的是,对于许多 IDE 中的类型检查工具来说(PyCharm https://en.wikipedia.org/wiki/PyCharm and PyDev https://en.wikipedia.org/wiki/PyDev我想到的)是有限的,因为它们没有任何关于对象类型的指示。因此,他们尝试以 50% 左右的成功率推断类型(如演示中所述)。
从类型提示演示中选取两张重要的幻灯片:
为什么要输入提示?
-
帮助输入检查器:通过暗示您希望对象成为什么类型,类型检查器可以轻松检测到您是否传递了一个类型不符合预期的对象。
-
帮助文档:查看您的代码的第三人将知道预期的内容,因此,如何使用它而无需获得它们
TypeErrors
.
-
帮助 IDE 开发更准确、更强大的工具:当知道您的对象是什么类型时,开发环境将更适合建议适当的方法。您可能在某些时候使用某些 IDE 经历过这种情况,点击
.
并弹出未为对象定义的方法/属性。
为什么使用静态类型检查器?
-
更快发现错误: 我相信这是不言而喻的。
-
您的项目越大,您就越需要它: 再说一遍,有道理。静态语言提供了鲁棒性和控制性
动态语言缺乏。您的应用程序越大、越复杂,控制力和可预测性就越高(从
行为方面)您需要的。
-
大型团队已经在运行静态分析:我猜这验证了前两点。
作为这个小介绍的结束语: 这是一optional据我了解,引入它是为了获得静态类型的一些好处。
你一般do not需要担心它并且确实不需要使用它(特别是在使用Python作为辅助脚本语言的情况下)。在开发大型项目时应该很有帮助它提供了急需的稳健性、控制和额外的调试功能.
使用 mypy 进行类型提示:
为了使这个答案更加完整,我认为进行一些演示是合适的。我将使用mypy http://mypy-lang.org/,该库激发了 PEP 中呈现的类型提示。这篇文章主要是为那些遇到这个问题并想知道从哪里开始的人写的。
在此之前,让我重申以下几点:PEP 484 https://www.python.org/dev/peps/pep-0484/不强制执行任何事情;它只是为功能设定一个方向
注释和建议指南how可以/应该执行类型检查。您可以注释您的函数并
你想暗示多少就暗示多少;无论是否存在注释,您的脚本仍然会运行,因为 Python 本身不使用它们。
无论如何,正如 PEP 中所述,提示类型通常应采用三种形式:
- 函数注释(PEP 3107 https://www.python.org/dev/peps/pep-3107/).
- 内置/用户模块的存根文件。
- Special
# type: type
补充前两种形式的注释。 (看:什么是变量注释? https://stackoverflow.com/questions/39971929/what-are-variable-annotations-in-python-3-6/39973133#39973133Python 3.6 更新# type: type
评论)
此外,您还需要将类型提示与新的typing https://docs.python.org/3/library/typing.html模块引入于Py3.5
。其中,许多(附加)ABCs https://en.wikipedia.org/wiki/Class_(computer_programming)#Abstract_and_Concrete(抽象基类)与辅助函数和装饰器一起定义,用于静态检查。大多数 ABC 位于collections.abc
都包括在内,但在一个generic表单以允许订阅(通过定义__getitem__()
方法)。
对于任何有兴趣更深入解释这些内容的人,mypy documentation http://mypy.readthedocs.org/en/latest/写得非常好,并且有很多代码示例演示/描述其检查器的功能;这绝对值得一读。
函数注释及特殊注释:
首先,观察使用特殊注释时我们可以获得的一些行为很有趣。特别的# type: type
评论
如果无法直接推断对象的类型,可以在变量赋值期间添加以指示对象的类型。简单的作业是
通常很容易推断,但其他的,如列表(就其内容而言)则不能。
Note:如果我们想使用任何导数容器并需要指定该容器的内容must使用generic类型来自typing
模块。这些支持索引。
# Generic List, supports indexing.
from typing import List
# In this case, the type is easily inferred as type: int.
i = 0
# Even though the type can be inferred as of type list
# there is no way to know the contents of this list.
# By using type: List[str] we indicate we want to use a list of strings.
a = [] # type: List[str]
# Appending an int to our list
# is statically not correct.
a.append(i)
# Appending a string is fine.
a.append("i")
print(a) # [0, 'i']
如果我们将这些命令添加到文件中并使用解释器执行它们,一切都会正常工作print(a)
只是打印
列表的内容a
. The # type
评论已被丢弃,被视为没有附加语义的普通注释.
通过运行这个mypy
,另一方面,我们得到以下响应:
(Python3)jimmi@jim: mypy typeHintsCode.py
typesInline.py:14: error: Argument 1 to "append" of "list" has incompatible type "int"; expected "str"
表明有一个列表str
对象不能包含int
,从静态角度来说,这是健全的。这可以通过遵守类型来解决a
并且仅附加str
对象或通过更改内容的类型a
表明任何值都是可接受的(直观地执行List[Any]
after Any
已导入自typing
).
表单中添加函数注释param_name : type
在函数签名中的每个参数之后,使用以下命令指定返回类型-> type
结束函数冒号之前的符号;所有注释都存储在__annotations__
该函数的属性以方便的字典形式呈现。使用一个简单的示例(不需要来自typing
模块):
def annotated(x: int, y: str) -> bool:
return x < y
The annotated.__annotations__
属性现在具有以下值:
{'y': <class 'str'>, 'return': <class 'bool'>, 'x': <class 'int'>}
如果我们是一个完全的新手,或者我们熟悉 Python 2.7 概念,因此不知道TypeError
潜伏在比较中annotated
,我们可以执行另一次静态检查,捕获错误并省去一些麻烦:
(Python3)jimmi@jim: mypy typeHintsCode.py
typeFunction.py: note: In function "annotated":
typeFunction.py:2: error: Unsupported operand types for > ("str" and "int")
除此之外,使用无效参数调用函数也会被捕获:
annotated(20, 20)
# mypy complains:
typeHintsCode.py:4: error: Argument 2 to "annotated" has incompatible type "int"; expected "str"
这些基本上可以扩展到任何用例,并且捕获的错误比基本调用和操作更进一步。你的类型
可以检查确实非常灵活,我只是对其潜力进行了一些小介绍。一看在typing
模块,该
PEP 或mypy
文档将使您对所提供的功能有更全面的了解。
存根文件:
存根文件可用于两种不同的非互斥情况:
- 您需要对不想直接更改函数签名的模块进行类型检查
- 您想要编写模块并进行类型检查,但还想要将注释与内容分开。
什么存根文件(扩展名为.pyi
) 是您正在制作/想要使用的模块的带注释的接口。他们包含
您想要进行类型检查的函数的签名,并丢弃函数的主体。为了感受这一点,给定一组
名为的模块中的三个随机函数randfunc.py
:
def message(s):
print(s)
def alterContents(myIterable):
return [i for i in myIterable if i % 2 == 0]
def combine(messageFunc, itFunc):
messageFunc("Printing the Iterable")
a = alterContents(range(1, 20))
return set(a)
我们可以创建一个存根文件randfunc.pyi
,如果我们愿意的话,我们可以在其中设置一些限制。缺点是
当试图理解假设的内容时,没有存根查看源代码的人将无法真正获得注释帮助
要传递到哪里。
无论如何,存根文件的结构非常简单:添加所有带有空主体的函数定义(pass
填充)和
根据您的要求提供注释。在这里,我们假设我们只想与int
我们的容器的类型。
# Stub for randfucn.py
from typing import Iterable, List, Set, Callable
def message(s: str) -> None: pass
def alterContents(myIterable: Iterable[int])-> List[int]: pass
def combine(
messageFunc: Callable[[str], Any],
itFunc: Callable[[Iterable[int]], List[int]]
)-> Set[int]: pass
The combine
函数给出了为什么您可能想要在不同文件中使用注释的指示,它们有时会造成混乱
代码并降低可读性(Python 的一大禁忌)。您当然可以使用类型别名,但这有时会带来更多的困惑
有帮助(所以明智地使用它们)。
这应该会让您熟悉 Python 中类型提示的基本概念。尽管使用的类型检查器已经mypy
您应该逐渐开始看到更多的弹出窗口,其中一些在 IDE 内部(PyCharm http://blog.jetbrains.com/pycharm/2015/11/python-3-5-type-hinting-in-pycharm-5/,) 和其他作为标准 Python 模块。
当我找到它们时(或者如果有建议),我会尝试在下面的列表中添加其他检查器/相关包。
我所知道的跳棋:
-
Mypy http://mypy-lang.org/: 如此处所述。
-
PyType https://github.com/google/pytype:通过谷歌,使用与我收集的不同的符号,可能值得一看。
相关包/项目:
-
打字: https://github.com/python/typeshed/官方 Python 存储库包含标准库的各种存根文件。
The typeshed
项目实际上是您可以查看如何在您自己的项目中使用类型提示的最佳位置之一。我们举个例子the __init__邓德斯的Counter class https://github.com/python/typeshed/blob/master/stdlib/3/collections.pyi#L78在相应的.pyi
file:
class Counter(Dict[_T, int], Generic[_T]):
@overload
def __init__(self) -> None: ...
@overload
def __init__(self, Mapping: Mapping[_T, int]) -> None: ...
@overload
def __init__(self, iterable: Iterable[_T]) -> None: ...
Where _T = TypeVar('_T')用于定义泛型类 http://mypy.readthedocs.org/en/latest/generics.html#defining-generic-classes。为了Counter
类我们可以看到它可以在其初始值设定项中不带任何参数,也可以获取单个Mapping
从任何类型到int
or采取一个Iterable
任何类型。
Notice: 有件事我忘记说了,typing
模块已被引入临时基础. From PEP 411 https://www.python.org/dev/peps/pep-0411/:
临时包可能会在“升级”到“稳定”状态之前对其 API 进行修改。一方面,这种状态为包提供了正式成为 Python 发行版一部分的好处。另一方面,核心开发团队明确表示,对软件包 API 的稳定性不做出任何承诺,下一个版本可能会发生变化。虽然这被认为是不太可能的结果,但如果对其 API 或维护的担忧被证明是有根据的,此类软件包甚至可能会在没有弃用期的情况下从标准库中删除。
因此,对这里的事情持保留态度;我怀疑它是否会被删除或以重大方式改变,但人们永远无法知道。
** Another topic altogether, but valid in the scope of type-hints: PEP 526: Syntax for Variable Annotations https://docs.python.org/3.6/whatsnew/3.6.html#pep-526-syntax-for-variable-annotations is an effort to replace # type
comments by introducing new syntax which allows users to annotate the type of variables in simple varname: type
statements.
See 什么是变量注释? https://stackoverflow.com/questions/39971929/what-are-variable-annotations-in-python-3-6/39973133#39973133,如前所述,对这些内容进行简要介绍。