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

Python 3.5中的类型提示是什么?,python,python-3.x,python-3.5,type-hinting,Python,Python 3.x,Python 3.5,Type Hinting,Python 3.5中最受关注的特性之一是类型提示 和中提到了类型提示的示例,同时也提到了负责任地使用类型提示。有人能详细解释一下它们,什么时候应该使用,什么时候不应该使用吗?我建议通过打字提示来阅读和观看 简而言之:字体暗示就是这些词的字面意思。提示正在使用的对象的类型 由于Python的动态特性,推断或检查所使用对象的类型尤其困难。这一事实使得开发人员很难理解他们没有编写的代码中到底发生了什么,最重要的是,对于许多IDE中发现的类型检查工具(我也想到了),这些工具由于没有任何对象类型的指示器

Python 3.5中最受关注的特性之一是类型提示

和中提到了类型提示的示例,同时也提到了负责任地使用类型提示。有人能详细解释一下它们,什么时候应该使用,什么时候不应该使用吗?

我建议通过打字提示来阅读和观看

简而言之:字体暗示就是这些词的字面意思。提示正在使用的对象的类型

由于Python的动态特性,推断或检查所使用对象的类型尤其困难。这一事实使得开发人员很难理解他们没有编写的代码中到底发生了什么,最重要的是,对于许多IDE中发现的类型检查工具(我也想到了),这些工具由于没有任何对象类型的指示器而受到限制。因此,他们试图推断出(如演示中所述)成功率约为50%的类型


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

为什么键入提示?
  • 帮助类型检查器:通过提示您希望对象是什么类型,类型检查器可以轻松检测是否传递了一个类型不符合预期的对象
  • 文档帮助:第三方查看您的代码时,会知道您希望在哪里使用它,并且不会让他们看到
    类型错误
  • 有助于IDE开发更准确、更健壮的工具:开发环境将更适合在知道对象类型时建议适当的方法。您可能在某些IDE中遇到过这种情况,点击
    ,并弹出未为对象定义的方法/属性
  • 为什么使用静态类型检查器?
    • 尽早发现bug:我相信这是不言而喻的
    • 项目越大,您就越需要它:同样,这是有意义的。静态语言提供了健壮性和 缺乏动态语言。应用程序越大、越复杂,控制和可预测性就越强(从 行为方面)你需要的
    • 大型团队已经在运行静态分析了:我猜这验证了前两点
    作为这个小介绍的结束语:这是一个可选的功能,据我所知,它的引入是为了获得静态键入的一些好处

    通常不需要担心它,而且肯定不需要使用它(特别是在使用Python作为辅助脚本语言的情况下)。在开发大型项目时,它应该很有帮助,因为它提供了急需的健壮性、控制和额外的调试功能


    用mypy键入提示: 为了使这个答案更完整,我认为进行一点演示是合适的。我将使用一个库,它激发了PEP中显示的类型提示。这本书主要是写给任何碰到这个问题并想知道从哪里开始的人的

    在此之前,让我重申以下几点:不强制执行任何内容;它只是为功能设定一个方向 注释和建议如何执行类型检查的指南。您可以注释您的函数和 你想暗示多少就暗示多少;无论是否存在注释,脚本仍将运行,因为Python本身不使用注释

    无论如何,正如政治公众人物中所述,暗示类型通常应采取三种形式:

    • 函数注释()
    • 内置/用户模块的存根文件
    • 特殊的
      #类型:输入补充前两种形式的注释。(请参阅:,了解有关
      #type:type
      注释的Python 3.6更新)
    此外,您还需要将类型提示与
    Py3.5
    中引入的新模块结合使用。在它中,定义了许多(附加的)(抽象基类)以及用于静态检查的辅助函数和装饰器。
    集合中的大多数abc.abc
    都包含在内,但为了允许订阅(通过定义
    \uuuu getitem\uuuuuuuuuuuuuuo()
    方法),它们是以通用形式存在的

    对于任何对更深入的解释感兴趣的人来说,编写得非常好,并且有很多代码示例演示/描述其检查器的功能;这绝对值得一读

    功能注释和特殊注释: 首先,观察我们在使用特殊注释时的一些行为是很有趣的。特殊
    #类型:类型
    注释 如果无法直接推断对象的类型,则可以在变量指定期间添加,以指示对象的类型。简单的作业是 通常很容易推断,但其他的,如列表(就其内容而言),则不能

    注意:如果我们想使用容器的任何衍生工具,并且需要指定该容器的内容,我们必须使用
    键入模块中的通用类型这些支持索引。

    # 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']
    
    如果我们将这些命令添加到一个文件中,并使用解释器执行它们,那么一切都会正常工作,并且打印(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
    ,静态地说,它是正确的。这可能是金融机构
    def annotated(x: int, y: str) -> bool:
        return x < y
    
    {'y': <class 'str'>, 'return': <class 'bool'>, 'x': <class 'int'>}
    
    (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"
    
    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 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
    
    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: ...
    
    def greeting(name: str) -> str:
        return 'Hello ' + name
    
    class C1:
        def __init__(self):
            self.idn = 1
        def add(self, ic: int):
            return self.idn + ic
    
    c1 = C1()
    c1.add(2)
    
    c1.add(c1)