Python 3.5 中的类型提示是什么?

2024-03-11

Python 3.5 中最受关注的功能之一是类型提示.

一个例子类型提示中提到本文 http://lwn.net/Articles/650904/ and this one http://lwn.net/Articles/640359/同时还提到负责任地使用类型提示。有人可以详细解释一下它们以及何时应该使用它们以及何时不应该使用它们吗?


我建议阅读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% 左右的成功率推断类型(如演示中所述)。


从类型提示演示中选取两张重要的幻灯片:

为什么要输入提示?

  1. 帮助输入检查器:通过暗示您希望对象成为什么类型,类型检查器可以轻松检测到您是否传递了一个类型不符合预期的对象。
  2. 帮助文档:查看您的代码的第三人将知道预期的内容,因此,如何使用它而无需获得它们TypeErrors.
  3. 帮助 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,如前所述,对这些内容进行简要介绍。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python 3.5 中的类型提示是什么? 的相关文章

  • 分配列表的多个值

    我很想知道是否有一种 Pythonic 方式将列表中的值分配给元素 为了更清楚 我要求这样的事情 myList 3 5 7 2 a b c d something myList So that a 3 b 5 c 7 d 2 我正在寻找比手
  • sy.sympify(str(表达式)) 不等于表达式

    据我了解 str将 SymPy 表达式转换为字符串并sympify将字符串转换为 SymPy 表达式 因此 我希望以下内容成立 对于合理的表达 gt gt gt sy sympify str expr expr True 我尝试过这个 确实
  • 如何使用 python、openCV 计算图像中的行数

    我想数纸张 所以我正在考虑使用线条检测 我尝试过一些方法 例如Canny HoughLines and FLD 但我只得到处理过的照片 我不知道如何计算 有一些小线段就是我们想要的线 我用过len lines or len contours
  • 计算熊猫数据帧几个月的总和

    我有一个 pandas 数据框 如下所示 ID Year R1 R1 f KAR1 20201001 1 5 KAR1 20201101 2 6 KAR1 20201201 3 7 KAR1 20210101 4 8 KAR1 202102
  • Python函数组成

    我尝试使用良好的语法来实现函数组合 这就是我所得到的 from functools import partial class compfunc partial def lshift self y f lambda args kwargs s
  • 如何将 numpy rearray 的子集转换为连续数组?

    我有一个recarray来自读取 csv 文件 我有兴趣将列的子集转换为连续浮点数组 我想避免将它们转换为列表或将它们一一堆叠 我尝试了中的建议https stackoverflow com a 11792956 https stackov
  • 如何在 numpy 数组中查找并保存重复的行?

    我有一个数组 例如 Array 1 1 1 2 2 2 3 3 3 4 4 4 5 5 5 1 1 1 2 2 2 我想要输出以下内容的东西 Repeated 1 1 1 2 2 2 保留重复行的数量也可以 例如 Repeated 1 1
  • 烧瓶 - 404 未找到

    我是烧瓶开发的新手 这是我在烧瓶中的第一个程序 但它向我显示了这个错误 在服务器上找不到请求的 URL 如果您输入了网址 请手动检查拼写并重试 这是我的代码 from flask import Flask app Flask name ap
  • 样本()和r样本()有什么区别?

    当我从 PyTorch 中的发行版中采样时 两者sample and rsample似乎给出了类似的结果 import torch seaborn as sns x torch distributions Normal torch tens
  • dask apply:AttributeError:“DataFrame”对象没有属性“name”

    我有一个参数数据框 并对每一行应用一个函数 该函数本质上是几个 sql queries 和对结果的简单计算 我正在尝试利用 Dask 的多处理 同时保持结构和界面 下面的例子有效并且确实有显着的提升 def get metrics row
  • Pandas如何按时间段过滤DataFrame

    我有一个包含下表的文件 Name AvailableDate totalRemaining 0 X3321 2018 03 14 13 00 00 200 1 X3321 2018 03 14 14 00 00 200 2 X3321 20
  • Bokeh 中单独的节点和边缘悬停工具?

    我正在尝试为 Bokeh 中的节点和边缘获取单独的悬停工具提示 但未能使其正常工作 有人可以指出我做错了什么吗 我相信代码应该如下所示 from bokeh io import show output notebook from bokeh
  • 一个类似 dict 的 Python 类

    我想编写一个自定义类 其行为类似于dict 所以 我继承自dict 不过 我的问题是 我是否需要创建一个私有的dict我的成员 init 方法 我不明白这个有什么意义 因为我已经有了dict如果我只是继承自的行为dict 谁能指出为什么大多
  • 如何在python 3.6.5中通过变量创建子元素

    我的代码是 import xml etree ElementTree as ET from lxml import etree var1
  • 如何在 Python 中跟踪日志文件?

    我想在 Python 中提供 tail F 或类似内容的输出 而无需阻塞或锁定 我找到了一些非常旧的代码来做到这一点here http code activestate com recipes 436477 filetailpy 但我认为现
  • 无法将matplotlib安装到pycharm

    我最近开始使用Python速成课程学习Python编程 我陷入困境 因为我无法让 matplotlib 在 pycharm 中工作 我已经安装了pip 我已经通过命令提示符使用 pip 安装了 matplotlib 现在 当我打开 pych
  • 更改用作函数全局作用域的字典

    我想做一个 purePython 的装饰器 其中一部分是能够有选择地禁止访问函数的全局范围 有没有一种方法可以以编程方式更改哪个字典事物充当函数的全局 外部作用域 因此 例如在下面我希望能够拦截对f in h并抛出错误 但我想允许访问g因为
  • 有没有办法拉伸整个显示图像以适应给定的分辨率?

    我最近一直在使用pygame制作游戏 遇到了一个小问题 基本上 我希望能够将屏幕上的整个图像 我已经传输到它的所有内容 拉伸到用户将窗口大小调整到的分辨率 我在 pygame 和堆栈溢出的文档中搜索了很多 但我似乎找不到答案 这可能吗 我的
  • 如何使用logging.conf文件使用RotatingFileHandler将所有内容记录到文件中?

    我正在尝试使用RotatingHandler用于 Python 中的日志记录目的 我将备份文件保留为 500 个 这意味着我猜它将创建最多 500 个文件 并且我设置的大小是 2000 字节 不确定建议的大小限制是多少 如果我运行下面的代码
  • Python matplotlib:将轴标签/图例从粗体更改为常规粗细

    我正在尝试制作一些出版质量的图 但遇到了一个小问题 默认情况下 matplotlib 轴标签和图例条目的权重似乎比轴刻度线重 是否有办法强制轴标签 图例条目与刻度线的重量相同 import matplotlib pyplot as plt

随机推荐