Python 3.5 中最受关注的特性之一是 类型提示 .
的例子类型提示 在 this article 中提到和 this one同时还提到负责任地使用类型提示。有人可以解释更多关于它们的信息,何时应该使用,何时不使用?
最佳答案
我建议阅读 PEP 483和 PEP 484并观看 this presentation来自 Guido关于类型提示。
简而言之 :类型提示就是字面上的意思。您暗示了您正在使用的对象的类型。
由于 Python 的动态特性,推断或检查正在使用的对象的类型特别困难。这一事实使开发人员难以理解他们尚未编写的代码究竟发生了什么,最重要的是,对于许多 IDE(PyCharm 和 PyDev)中发现的类型检查工具来说,这些工具是有限的事实上,他们没有任何关于对象类型的指示。因此,他们试图以大约 50% 的成功率(如演示中提到的)推断类型。
从类型提示演示中获取两张重要的幻灯片:
为什么要输入提示?
TypeErrors
. .
并弹出未为对象定义的方法/属性。 为什么要使用静态类型检查器?
缺乏动态语言。您的应用程序越大越复杂,控制力和可预测性就越强(从
行为方面)您需要。
作为这个简短介绍的结束语 : 这是一个 可选 功能,据我所知,引入它是为了获得静态类型的一些好处。
你一般不要需要担心它和绝对不需要使用它(特别是在您使用 Python 作为辅助脚本语言的情况下)。它在开发大型项目时应该会有所帮助,因为它提供了急需的稳健性、控制和额外的调试功能。
使用 mypy 进行类型提示 :
为了让这个回答更完整,我觉得稍微演示一下比较合适。我将使用
mypy
,启发了类型提示的库,因为它们出现在 PEP 中。这主要是为遇到这个问题并想知道从哪里开始的任何人而写的。在我这样做之前,让我重申以下内容:PEP 484不强制执行任何事情;它只是为功能设定一个方向
的注释和建议指南怎么样可以/应该执行类型检查。你可以注释你的函数和
提示尽可能多的东西;无论是否存在注释,您的脚本仍将运行,因为 Python 本身不使用它们。
无论如何,如 PEP 中所述,提示类型通常应采用三种形式:
# type: type
补充前两种形式的注释。 (请参阅: What are variable annotations? # type: type
评论的 Python 3.6 更新)此外,您需要将类型提示与新的
typing
结合使用。 Py3.5
中引入的模块.其中,许多(附加)ABCs (抽象基类)与辅助函数和装饰器一起定义,用于静态检查。大多数 ABC 在 collections.abc
包括在内,但以通用形式允许订阅(通过定义 __getitem__()
方法)。对于对这些更深入的解释感兴趣的任何人,
mypy documentation
写得很好,有很多代码示例演示/描述了他们的检查器的功能;绝对值得一读。函数注解和特殊注释:
首先,观察我们在使用特殊注释时可以获得的一些行为是很有趣的。特价
# type: type
评论如果不能直接推断,可以在变量赋值期间添加以指示对象的类型。简单的任务是
通常很容易推断,但其他人,如列表(关于其内容),则不能。
注:如果我们想使用容器的任何派生类并且需要为该容器指定内容,我们 必须使用 通用 类型来自
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
. # 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]
导入 Any
后使用 typing
直观地执行)。函数注解以
param_name : type
的形式添加在函数签名中的每个参数和返回类型之后使用 -> type
指定结束函数冒号前的符号;所有注释都存储在 __annotations__
中以方便的字典形式显示该函数的属性。使用一个简单的例子(不需要来自 typing
模块的额外类型):def annotated(x: int, y: str) -> bool:
return x < y
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"
这些基本上可以扩展到任何用例,并且捕获的错误比基本调用和操作扩展得更远。你的类型can check for 真的很灵活,我只是给了它潜力的一个小高峰。看看
typing
模块,PEP 或
mypy
文档将使您更全面地了解所提供的功能。stub 文件:
stub 文件可用于两种不同的非互斥情况:
stub 文件(扩展名为
.pyi
)是您正在制作/想要使用的模块的带注释的接口(interface)。它们包含您要使用丢弃的函数体进行类型检查的函数的签名。为了感受这一点,给定一个集合
名为
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)
我们可以创建一个 stub 文件 randfunc.pyi
,如果我们愿意,我们可以在其中设置一些限制。缺点是在试图理解应该是什么时,没有 stub 查看源代码的人将无法真正获得注释帮助
要经过哪里。
无论如何, stub 文件的结构非常简单:添加所有具有空体的函数定义(
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
combine
函数给出了为什么你可能想要在不同的文件中使用注释的指示,它们有时会困惑代码并降低可读性(Python 的大禁忌)。你当然可以使用类型别名,但有时比它更令人困惑
帮助(所以明智地使用它们)。
这应该会让您熟悉 Python 中类型提示的基本概念。即使使用的类型检查器已经
mypy
你应该逐渐开始看到更多的弹出窗口,一些在 IDE 内部( PyCharm ,)和其他作为标准 Python 模块。当我找到它们(或如果建议)时,我将尝试在以下列表中添加其他检查器/相关包。
我知道的跳棋 :
相关包/项目 :
typeshed
project 实际上是您可以查看如何在您自己的项目中使用类型提示的最佳场所之一。我们以the __init__
dunders of the Counter
class为例在相应的 .pyi
文件: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')
is used to define generic classes .对于 Counter
我们可以看到它可以在其初始化器中不带任何参数,获得单个 Mapping
从任何类型到 int
或拨打 Iterable
任何类型。通知 :我忘记提及的一件事是
typing
模块是临时引入的。来自 PEP 411 :A provisional package may have its API modified prior to "graduating" into a "stable" state. On one hand, this state provides the package with the benefits of being formally part of the Python distribution. On the other hand, the core development team explicitly states that no promises are made with regards to the the stability of the package's API, which may change for the next release. While it is considered an unlikely outcome, such packages may even be removed from the standard library without a deprecation period if the concerns regarding their API or maintenance prove well-founded.
所以拿一撮盐来这里;我怀疑它是否会被删除或以重要的方式改变,但人们永远无法知道。
** 完全是另一个主题,但在类型提示范围内有效:
PEP 526
: Syntax for Variable Annotations是努力取代# type
通过引入新语法来注释,允许用户以简单的方式注释变量类型 varname: type
声明。见 What are variable annotations? ,如前所述,对这些进行简要介绍。
关于python - Python 3.5 中的类型提示是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32557920/