Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发。

3、接口存根文件

这个选项允许你如下图一般保存你的代码:

并在原文件的旁边添加一个扩展名为pyi的文件:

接口文件并不是一个新事物,C/C++已经用了十几年了。因为Python是一种解释语言,它通常不需要接口文件。但是由于计算机科学中的每一个问题都可以通过增加一个新的中间层来解决,那么我们就可以添加一层来存储类型信息。

这样做的优点是:

√ 你不需要修改源代码,且在任何python版本下都可以工作,因为解释器不会处理这些文件。

√ 在存根文件中,你可以使用最新的语法(比如,类型标注)。因为在应用的执行过程中这些根本不会被查看。

√ 因为不需要修改你的源代码,这就意味着添加类型提示的过程中不会导致新的错误,你添加的内容也不会和其他linter工具产生冲突。

√ 这是一种经过测试的设计,typeshed项目使用接口存根文件对整个标准库添加了类型提示,并加入了一些流行的库,比如:requests, yaml, dateutil等等。

√ 可以用来对不是你的代码或者你不能轻易修改的代码添加类型提示。

现在要对这种方法列出罚单了:

· 你需要复制你的代码库,也就是说每个方程现在都有两种定义(注意你不需要重复代码的主体或默认参数,使用…-省略号-做占位符即可)。

· 现在你有一些额外的文件需要打包并要和源代码一起装载。

· 你不太可能注释掉函数中的内容了(在上面的例子中,这会影响到pyi文件中方法内部的两个方法和局部变量)。

· 没法确保实现的文件和存根文件相匹配(而且IDE总是会优先使用存根文件中的定义)。

· 然而,最严重的一张罚单是,你不能对使用存根文件添加的类型提示进行类型检查。通过存根文件来添加类型提示这种方式是被设计用来对使用库函数的代码进行类型检查的,而不是对你的代码库进行类型检查的。

最后两个缺点使得检测使用存根文件添加类型提示的代码是否同步变得非常困难。在当下的形式中,类型存根文件是一种给你的用户提供类型提示功能的方法,但并不能给你带来便利,并且很难维护。为了解决这些问题,我承担起了将存根文件和源文件在mypy中合并在一起的任务;理论上,这将同时解决这两个问题。你可以在python/mypy ~ issue 5208下追踪项目的进展。

4、文档字符串

将类型信息添加到文档字符串中也是可行的。尽管这不是为Python设计的类型提示功能框架的一部分,它依旧得到了大部分主流IDE的支持。这大概是实现这一目标的传统方式吧。

从好的一面出发:

√ 适用于任何Python版本,它的定义在PEP-257中。

√ 不和其他linter工具冲突,因为大多数工具不检查文档字符串,通常只检查代码部分。

然而,这种方法存在以下严重缺陷:

· 没有一种标准的方法来声明复杂数据类型提示(比如,int或bool)。Pycharm有它特有的方法,但是像Sphinx就使用了一种完全不同的方法。

· 需要修改文档,并且因为没有工具来检查它的有效性所以很难保证数据的及时性和准确性。

· 文档字符串和添加有类型提示的代码的兼容性不好。试想当类型标注和文档字符串同时生效时,哪个优先呢?

添加什么?

现在让我们深入细节。如果需要查看可添加的类型信息的具体列表,请参考官方文档。在这里,我仅做一个3分钟的简述帮助你理解它的思想。将数据类型分为两类:标准类型和鸭子类型(协议)。

1、标准类型

标准类型是指在python解释器中有名称的类型。比如所有的内置类型(int, bolean, float, type, object等等)。然后这些一般的数据类型主要以容器的形式体现:

对于复合类型,一遍一遍的重复定义显得很笨重。所以系统允许你通过下面的方式对复合类型进行命名:

我们甚至可以对内置的数据类型重新命名,这在避免例如给一个函数以错误的顺序传入两个类型一样的参数这类的错误时很有用:

对于命名元组,你可以直接附上自己的类型信息(注意,它和python3.7及great attrs库中的数据类非常相似。)

你还可以指定类型为多种指定类型中的一个:

我们还可以用TypeVar函数来定义自己的一般变量:

最后,在不需要检查的地方可以使用Any这种类型提示来禁止类型检查:

2、鸭子类型 – 协议

在这种情况下,与其说是使用类型去定义更像是用python语言来定义,并遵守这样的定律:如果一个生物像鸭子一样嘎嘎叫又表现的很像鸭子,那么无论是出于什么样的目的都可以认为这个生物就是鸭子。在本例中,你需要在对象上定义想要的操作和属性,而不是直接声明它们的类型。这里的依据请查看PEP-544~Protocols。

哈,抓到你了

一旦你开始在代码库中添加类型提示,有时可能会遇到一些奇怪的情况。那时你可能像下面这只海豹一样露出“这是什么鬼”的表情。

1、Python2/3间的差异

这里来快速地在一个类上实现__repr__方法:

这段代码是有bug的。在python3下运行是正确的,但在python2下不行,这是因为在python2环境中,解释器期望__repr__方法返回bytes类型的数据,然而Unicode_literals的引入使得返回值实际上为unicode类型的。本例中,将下一个版本的新特性引入意味着不可能编写一个同时满足python2和python3的类型需求的__repr__方法。你需要加入运行逻辑来使代码做正确的事情:

现在,要让IDE接收这种形式,你需要添加一些linter注释,这使得代码读起来很复杂。更重要的是,类型检查器的存在迫使你必须在运行中额外进行一次检查。

2、多个返回类型

假设你想编写一个函数,作用是将一个字符串或者整数乘以2。对此的一种尝试可能是:

你输入的类型是str或者int,你的返回值相应的也是str或int。然而,如果如上图中那样做,你实际上是在告诉类型提示输入的类型可以是这两种类型中的任意一种。因此,作为调用方,你需要声明调用的类型:

这种不便可能会让一些人通过定义返回值为any类型来避免麻烦。但是,这儿有一种更好的解决方案。类型提示系统允许你定义重载。重载的意思是对于一个给定类型的输入只会返回一个指定类型的输出。对于本例而言:

不过这也有不利的一面。此时你的静态linter工具正在抱怨你利用相同的名称重新定义函数。这是一个错误的告警,可以添加一个静态linter禁用注释标记(#pylint:disable=function-redefined)。

3、类型查找

试想你有一个类,它允许将其包含的数据表示成不同的类型,或者具有一个包含不同类型的字段。你希望用户有一个快捷简单的方式来引用它们,所以你添加了一个内置了类型名称的函数:

一旦运行你就会发现:

有人可能会问这到底是怎么回事。我给返回值的定义是float类型而不是test.A.float类型。出现这种混淆错误的原因时类型提示通过定义的位置出发评估每一个遇到的范围来解析类型。一旦找到匹配的名称,它就停止了。本例中类型提示所查找的第一层次是在类A中,在这里它找到了一个float(float函数)并进行了替换。

避免这类问题的解决办法是明确地定义我们不是想要任何float,而是只要内置的float(builtin.float):

值得注意的是,要做到这一点你还需要引入builtins同时为了避免在运行时出现这种问题,你可以使用typing.TYPE_CHECKING标志来指导类型提示,这个标志只有在linter工具执行期间为真,其余时刻都为假。

4、逆变参数

检查下面的例子。你定义了一个抽象的基本类,其包含了一些常规操作。然后你有一些具体的类,它们都只处理一种类型。控制类的创建来确保传递正确的类型,并且基本类是抽象的,这似乎是一个让人满意的设计:

然而当你运行类型linter工具进行检查时会发现:

这里的问题在于类中的参数是逆变的。这意味着在你的派生类中,必须处理父类中所有的类型。然而,你还可以在派生类中添加额外的类型。也就是说你只能扩展派生类中的函数参数,但不能以任何形式加以限制:

5、兼容性

看看你能否从下面的代码片段中发现错误:

如果你还没有想好,请试想如果你运行下面的脚本会发生什么:

如果你尝试运行它,这会运行失败并给出以下告警:

这是因为B是A的子类。进而B可以被装入一个A类的容器中(又因为B扩展了A,所以B能做的比A更多)。然而B的类方法不能被装入A类的容器,因为它不能近用一个参数来调用magic方法。此外,类型linter工具也不能指出这一点:

一个快速而简单的解决方法是通过一些手段确保B.magic方法可以在只有一个参数的情况下工作,比如将第二个参数设置为可选项。现在用我们所学到的来看下面的代码:

你觉得会发生什么?注意,我们将类方法移动到构造函数中,并没有做其他的修改。所以我们的脚本也需要一点小小的修改:

下面是运行时的告警,和之前的基本一致,只是现在是关于__init__而不是magic的:

那么你觉得mypy会说什么?如果去运行你会发现mypy选择保持沉默。没错,它会将这些标记为正确的,尽管在运行时失败了。mypy的创作者说这是因为类型失配太普遍了,以致于不能禁止__init__和__new__的不匹配问题。英文原文:https://www.bernat.tech/the-state-of-type-hints-in-python/

译者:舞象加冠

python怎么显示提示_Python中的类型提示(中)相关推荐

  1. 全面理解Python中的类型提示(Type Hints)

    众所周知,Python 是动态类型语言,运行时不需要指定变量类型.这一点是不会改变的,但是2015年9月创始人 Guido van Rossum 在 Python 3.5 引入了一个类型系统,允许开发 ...

  2. 第八章 函数中的类型提示

    应该强调的是,Python 仍将是一种动态类型的语言,即使按照惯例,作者也不希望强制类型提示 --Guido van Rossum, Jukka Lehtosalo, and Łukasz Langa ...

  3. php 类型提示,PHP中的类型提示(type hinting)功能介绍

    PHP中的类型提示(type hinting)功能介绍 这篇文章主要介绍了PHP中的类型提示(type hinting)功能介绍,本文讲解了类型提示的作用和使用方法以及使用示例,需要的朋友可以参考下 ...

  4. python 数据框缺失值_Python:处理数据框中的缺失值

    python 数据框缺失值 介绍 (Introduction) In the last article we went through on how to find the missing value ...

  5. python如何显示时间_python显示当前时间

    Python中怎么显示当前时间 用Python3编写一个程序显示当前北京时间,要CSS布局HTML小编今天和大家分享显示格式如下: 当前时间import timeprint(time.strftime ...

  6. java中map类型_Java中Map类型遍历的两种方式对比

    Java中Map类型是存储键值对数据的类型,在编程过程经常使用,进行遍历操作对于每个Java程序员都不会模式,下面总结两种常用的遍历方式(一种keySet,一种entrySet),通过对比让你明白使用 ...

  7. python label显示图片_python 实现在tkinter中动态显示label图片的方法

    在编程中我们往往会希望能够实现这样的操作:点击Button,选择了图片,然后在窗口中的Label处显示选到的图片.那么这时候就需要如下代码: from tkinter import * from tk ...

  8. python怎么显示结果_python中plot实现即时数据动态显示方法

    在Matlab使用Plot函数实现数据动态显示方法总结中介绍了两种实现即时数据动态显示的方法.考虑到使用python的人群日益增多,再加上本人最近想使用python动态显示即时的数据,网上方法很少,固 ...

  9. python配置文件密码管理_python – 可以在django管理员中实现“下次登录时更改密码”类型功能吗?...

    我其实正在这样做的过程中.您需要三个组件:用户配置文件(如果您的站点上尚未使用),中间件组件和pre_save信号. 我的代码是在一个名为"帐户"的应用程序. # myprojec ...

最新文章

  1. 【Flutter】Flutter 混合开发 ( 安卓端向 Flutter 传递数据 | FlutterFragment 数据传递 | FlutterActivity 数据传递 )
  2. envi5.2中文版
  3. (总结)Nginx配置文件nginx.conf中文详解
  4. android o preview 3,Android O Preview 之 通知渠道(Notification Channels)
  5. Linux目录结构及作用
  6. 铁矿怎么来_铁矿期货今日创出新高908.5点 为何老有人错过行情
  7. 分类树/装袋法/随机森林算法的R语言实现
  8. CreateProcess的使用方法
  9. 奇怪的问题,再次启动jar包会导致bean对象失效?Unknown redis exception Cannot connect, Event executor group is terminated
  10. **print('人生苦短 我爱Python')**
  11. java快捷键 --_Java中的快捷方式“或分配”(| =)运算符
  12. LSGANs : Least Squares GAN(最小二乘GAN)--解决标准GAN生成的图片质量不高以及训练过程不稳定问题
  13. MTK 驱动开发(39)--低功耗分析工具
  14. 山寨版学子商城——成功上线!
  15. Mac安装telnet工具和使用
  16. android逆向 网易,Android逆向——网易云音乐排行榜api(上)
  17. Visio 安装后提示 Dos 共享冲突
  18. 操作系统实验七:动态分区分配方式的模拟
  19. 推广邮件客户端(一):让人纠结的POP3客户端
  20. 什么是网站服务器 域名 备案号,什么是网站服务器 域名 备案

热门文章

  1. 计算机机房吊顶保温,机房吊顶高度
  2. Java —— 引入无用包的影响及快速清理方法
  3. J酒店上海中心等入选2022年度中国最佳奢华酒店榜,地中海俱乐部获中国最受欢迎酒店品牌 | 美通社头条...
  4. 织梦dedecms如何制作手机网站
  5. 超能旗舰荣耀9X是怎样炼成的?黄景瑜为您揭秘
  6. ShowModal 关闭问题
  7. 关于showModal的坑
  8. 《惢客创业日记》2019.10.26(周六) 5G仅仅是速度快吗?(六)
  9. R语言-股票数据库(2)-股票日K线信息-未复权
  10. 【洛谷 3353】 在你窗外闪耀的星星