aop在项目中的实际运用_mypy在实际项目中的应用

110454e0fa53a31c27be99191664d6cc.png

我认为静态类型似乎被吹捧过高了。

尽管如此,mypy极低的侵入性能带来许多好处。关于如何在现有的Python项目中添加类型,以下是我的一些想法,大致按重要性排序。

首先确保mypy成功运行 

Mypy上手时两个很常见的问题有:

1.Mypy没有作为构建的一部分运行

2.mypy 虽然正在运行,但它没有找到任何源文件或只找到了一部分源文件

Mypy的“默认允许”特性使两者都极易出现。无论出现哪种情况,都会非常痛苦,因为最后人们应用的类型,其实并未被检查,因而问题会慢慢暴露出来,让人非常困惑。

要手动添加类型的地方

Mypy 可进行类型推断,即通过检查有关值的代码,基于上下文区分值的类型。但事实上,由于mypy“渐进式推断”的特点,(如果不确定,它将推断成Any类型),比起像Haskell等其他推断性的语言,在python中更需要手动提供类型。

我目前的想法是:你应该力求为所有函数实参和返回值1 (以及其他任何mypy需要帮助的地方)提供类型。

一般来说,变量不需要应用类型,尽管这可能有助于使你的代码更清晰,或者帮助处理你不理解的类型错误。

Opitional会被频繁使用

在实践中最重要的一种类型就是 Optional. Optional 被用于可为空的值. 举个例子:

287a2661e8a9293c08b8afb9d4241752.png

大量的代码会使用Optional配合其他类型使用。有了Optional,mypy就能够检查空值,无论该值被用在哪里。

Optional是一种简单的类型但它却能够查出大量的缺陷,它可能是整个类型检查体系中最好的部分。

考虑是否要包含你的测试

关于是否在类型检查中包含测试(即也对测试进行类型检查),我不知道有没有统一答案。有些项目确实能在 tests/  目录上运行mypy,有些则不能。

在类型检查2中包含测试的主要优点是:你能迅速发现应用类型和预期用法不一致,或mypy推断的类型与预期用法不符。

这在新的或没有太多类型应用的代码库中尤其有用。另外,测试也能用来改善IDE的 tab-completion

然而不利的一面就是,通常出于Mock(模拟)和Fake(伪造)的目的,测试有时会对你的代码进行一些古怪操作,而且,某些测试模式通过类型检查器可能有点困难 这虽然不是什么大问题,但似乎有点浪费时间,并且会削弱类型的优势。

有选择性地使用第三方stub(存根)

一些库包含大量运行时的元编程技巧. 因而这些库通常不会提供太多类型信息。

在程序中心使用了这些库,却不能获取类型信息,这会十分恼人。一些库有第三方Stub文件,例如sqlalchemy有sqlalchemy-stubs ,它会提供一些有用但不完全的类型。

这些库并非都有有用的第三方Stub。在撰写本文时,我对boto的任何第三方Stub都不信服。最好的方法似乎是在调用AWS / Openstack API时学会与Any一起使用(但要用moto进行彻底测试)。

偶尔需要应急措施

你偶尔会遇到这样的情况:代码正确但mypy无法分辨。这里有几种解决方法:

第一种(可能是最好的方法)就是用typing.cast,它会告诉  mypy 你知道的比它知道的更多。这将在整个代码中保持类型检查,除非通知 mypy做一个特定的更正。

第二种选择就是值显式设置为Any。这将禁用检查该特定值。如果所讨论的值是没有简单类型的复杂对象,则可以使用此方法。

第三种就是使用 # type: ignore 语法. 如果问题不在于确定特定类型,而在于mypy误认为被破坏了的某些不变类型,用这个会很方便。

考虑加一个注释去解释原因

优先选择一些严格性选项

Mypy的 mypy.ini 文件允许进行广泛的配置。我还没见过哪个实操项目避免使用mypy配置的。以下是我的首选:

  •  check_untyped_defs 使mypy尝试检查没有类型注释的函数内部。否则,对于类型注释级别较低的项目mypy很少检查。

  • no_implicit_optional 当你设定参数不是空值,但实际上它们可为空时,它将提示类型错误。

  • ignore_missing_imports  这个应谨慎使用,不要将其应用于整个mypy 中,否则会极大地增加由于错误导致重要代码检查失败的风险。用此配置选项来标记特定模块(或名称空间)即可。

一个可行的例子:

91fa03ceb1cfa34b0823ab49da9cbd82.png

一旦你的项目深度耦合了mypy,我建议最好去查看mypy提供的所有其他严格选项。从低严格度级别开始,朝着高严格度级别推进是一个好的策略。

如何调试类型问题

对于难懂的类型问题,这里给出两个策略来调试。

第一种:你可以将类型应用于出错类型周围,如变量、函数参数、循环迭代变量等。这样有助于将错误从难懂的那行代码中移动到更容易看出问题的地方。

第二:使用魔法般的mypy内置函数。reveal_type(expr)能使 mypy 打印出给定表达式类型的意见;reveal_locals() 则会让mypy打印出范围内所有变量的类型. 这两者中,我用 reveal_locals()  更多一些。

抽象,具体,可变和不变

Mypy 有具体的类型,如 List 和 Dict;也有抽象的类型,如 Sequence 和Mapping

一些抽象的类型还分可变和不可变的版本,例如Set 和 MutableSet ,Mapping 和 MutableMapping

因此我们需要去选择应用哪种类型及何时应用。

我的朋友Oli Russell提出以下策略:

  1. 让参数类型尽可能抽象

  • 这样能使调用者尽可能自由地传递他们想要的

  2.让返回类型(更)具体

  • 同样也是为了让调用者尽可能自由地使用返回值

以上与我的经验相符。如果你过于苛刻, 比如,你返回 Sequence 而不是 List, 那么别人之后还要去编辑你的返回类型才能达到他们的目的。

同样的, 太具体的参数类型也很麻烦。你会发现无法将自定义的类似dict的对象传递给函数。有的对象只定义了__getitem__,但它确实可以当成一个Dict来使用。

你可以查阅 collections.abc 的标准库文档,去找每种抽象类型中包含的方法。以下是最常用的:

  • Iterable

  • Sequence 和 MutableSequence

  • Mapping 和 MutableMapping

  • Set 和 MutableSet

另外还有其他考虑。也许你想要阻止调用者修改你要返回的东西 (可能是因为你正在内部使用它3)。在这种情况下,最好返回 Mapping 而不是Dict。

Typed dataclasses(类型化的数据类)

Python 3.7 引入了 dataclasses. 下面是一个可能的类定义,如果你的类主要包含数据 (而不是行为)。它能为你提供一个更简洁的语法。

726e7df0bf88c5a2fd1d4bce293929c0.png

类型系统也支持这样的类,来作为其值的类型。

但缺点就是,大量更改其数据表示形式的代码往往不是快速代码。如果一个不可变的 Mapping作用于程序中的大部分,那它会比有一系列中间数据类要更快。

TypedDict

在 mypy 的扩展库中还有一个typed dictionary  。自3.8版本起它在标准库里。

c478f73886debfc7edba3901acc74168.png

TypedDict 能让你通过类型系统来控制存在哪些键以及它们的键值是什么,这一点胜过平常用的Mapping[str, str]。

它能成为Typed dataclasses的一个有效替代方案,且通常速度更快。

泛型和类型变量

mypy包括对类型变量和泛型类型的支持. 似乎大多数人发现如List等使用起来简单自然,但当有新的类型被创建出来之后,代码往往倾向于将类型限制定义为基类。

但是不是所有的泛型都不符合规则 , 在各式各样的Python 代码中,泛型偶尔也有使用价值。

泛型允许变量的类型更灵活 ,但它会保持检查 ,举个例子:

2222495f720706508921bbe515f5bea0.png

另一个例子:

398d0a5b6afd694c8621904156275c37.png

泛型能让你定义专门作用于某种类型变量的类。下面这个例子中,我们将D绑定到一个特定的抽象基类。

de4065bacdd1f0409e05917d6ea4264f.png

我相信接下来几年这个将被广泛使用

ABCs vs Protocols

有时,需要将抽象类型应用于具有各种具体选项的事物(此处在实践中和使用泛型类型有交叉)。有两种方法可以做到这一点。

第一种:通过下面的方法命名父基类,子类将从该基类继承。

078dd9d50d3fb0072dffa00a235e335c.png

这里的 feed_animal 标记为采用Animal (一种抽象基类)。

第一种方法称为名义子类型化,作为在面向对象的语言中使用抽象类型的传统方式,大多数人应该熟悉。

还有第二种(相对于Python)较新的方法,在该方法中,您无需命名父类,而是命名一个有你所需方法的“协议”。

7313e1de66487c874f012df0313660d8.png

这里的feed_animal 被标记使用 Carnivore (一种协议)。注意,我不必将任何animal类标记为成员:如果它们具有相同类型的eat_meat方法,则它们将自动作为Carnivore的一部分

协议是“开放的”,因此任何具有匹配eat_meat方法的类都将被算作成员。这种方法叫做结构子类型化。有许多 built in protocols(内置协议),例如Sized,SupportsBytes,Container等。

如果你能控制足够多的类层次结构,则可以选择名义子类型,但是如果不能,则必须使用结构子类型。

与泛型类型一样,这个最好谨慎使用。希望绝大多数情况下,具体类型就够用了,这样就不必在代码库中填充大量协议和抽象基类了。

最后的提示

一些人太过于执迷类型了,我目睹了大量Haskell社区的人一头扎进自己的创作中无法自拔,变得痴痴傻傻,实在有点看不下去。

要小心变成类型狂!不要忽略这样一个事实:类型检查是修正错误的一种辅助,而勿满足于类型检查本身。

另请参阅

  • Dropbox是最早将mypy应用于其代码库的公司之一。对此他们也写了经验,读来十分有趣。"The Tangle"在许多Python项目中出现过。

注释:

  1. 强制执行此操作的相关配置选项是disallow_untyped_defs,但对现有项目立即启用它通常只会贪多嚼不烂。

  2. 请注意,你必须在与主代码库相同的mypy中运行测试。将测试分开各自运行是得不到任何好处的。

  3. 正如我在本文提到过的,避免在任何地方创建新集合的一个很好的理由是速度。用不可变的抽象类型标记返回类型有助于对此进行静态分析。

英文原文:http://calpaterson.com/mypy-hints.html
译者:ᐛ

e6eb955c900726c6fe4a8309e2b1c60f.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/259043.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

face alignment by 3000 fps系列学习总结(三)

训练 我们主要以3000fps matlab实现为叙述主体。 总体目标 我们需要为68个特征点的每一个特征点训练5棵随机树,每棵树4层深,即为所谓的随机森林。 开始训练 分配样本 事实上,对于每个特征点,要训练随机森林,我们需…

HDU 2049 不容易系列之(4)——考新郎( 错排 )

链接:传送门思路:错排水题,从N个人中选出M个人进行错排,即 C(n,m)*d[m]补充:组合数C(n,m)能用double计算吗?第二部分有解释 Part 1. 分别求出来组合数的分子和分母然后相除/******************************…

linux服务器选ubantu或centos_如何通过SSH连接阿里云上的Linux系统

首先SSH是啥,维基一下:Secure Shell(安全外壳协议,简称SSH)是一种加密的网络传输协议,可在不安全的网络中为网络服务提供安全的传输环境[1]。SSH通过在网络中创建安全隧道来实现SSH客户端与服务器之间的连接…

paypal之nodejs 框架 Kraken-js 源码分析

本文是基于 kraken-js 0.6.1 版本的 关于如何使用kraken-js 可以去看看官网的使用文档 点击这里 。kraken-js 是基于express之上的,目的在于让工程师更多的去关注代码逻辑,少关注自身的开发环境,所以他将express所有的一些公用的配置都写在了…

go build 参数_Go语言 通过go bulid -tags 实现编译控制

Go语言提供的build tag 条件编译特性,顾名思义,只有在特定条件下才会构建对应的代码。比如下面的源文件只有在设置debug构建标志时才会被构建:// build debugpackage mainvar buildMode "debug"可以用以下命令构建:go …

selinux 的管理

第十单元selinux 的管理一 显示及更改 SELINUX 模式getenforce ###显示selinux模式setenforce 0|1 ##0指permissive警告,1 表示 enforcing强制###vim /etc/sysconfig/selinux ###修改selinux开机状态###注:disable表示关闭&…

ubuntu15.10下安装opencv2.4.9python上调用opencv库

对于centos,可以参考:Install OpenCV-Python in Fedora 如果IPP难以下载可以在cmake时禁掉它,只需:cmake -DWITH_IPPOFF OpenCV3.3CUDA9.0 安装过程中遇到的问题,解析: https://blog.csdn.net/u014613745/a…

键盘改键软件_一秒五键,一键三招,万种光污染,杜伽K310樱桃轴机械键盘感受...

机械键盘我一直用的青轴,或者各种其他名字但其实本质就是青轴的。喜欢青轴那种清脆的声音,在我听来如同山间小溪流水般的叮咚。不过这声音在夜间分外的具有穿透力,更会在人身体不好的时候难以承受,所以每每用过之后却又不得不换回…

codeigniter钩子的使用

CodeIgniter 的钩子功能,使得我们可以在不修改系统核心文件的基础上,来改变或增加系统的核心运行功能。可是钩子究竟该怎么用呢?虽然不是很难,不过很多刚用ci的朋友可能还是不明白怎么用。 通过本文的简单实例,大家一下…

powerdesigner画关系图_想画好手绘,这些图你一定要画一下!

画好手绘除了对透视要深入了解掌握以及线条运用把握之外,还有很重要的就是要对空间物体的关系、比例、光影关系都要理解透彻。大体快可分割成多个x小体块。其实当年学习的绘画基础也是画好手绘的基础,画手绘依然需要去理解整体画面的空间黑白灰、物体穿插…

internetreadfile读取数据长度为0_【完结】TensorFlow2.0 快速上手手册

大家好,这是专栏《TensorFlow2.0》的第五篇文章,我们对专栏《TensorFlow2.0》进行一个总结。我们知道全新的TensorFlow2.0 Alpha已经于2019年3月被发布,新版本对TensorFLow的使用方式进行了重大改进,为了满足各位AI人对TensorFlow…

Facial Landmark Detection(人脸特征点检测)

原文地址:http://www.learnopencv.com/facial-landmark-detection/#comment-2471797375 作为计算机视觉研究员,我们很早就开始研究人脸。人脸分析领域最广为人知的就是人脸识别(face recognition).但是为了识别一幅图像中的人脸&…

Java中的Error和Exceptiond的异同点

Error和Exception的异同点: (1)Error类和Exception类都继承超类Java.lang.Throwable (2)Error:一般指与虚拟机相关的问题,如系统崩溃,内存溢出等。对于这类错误,仅靠程序…

superviseddescent (SDM C++11实现)环境配置

今天试着用了一下SDM的C11实现,本来以为挺简单的,可是配置环境还是花了一些时间。为了给自己留下一些记忆,特把配置过程记录下来。 这个实现是C11的版本,是一个通用版本,里面包含了很多的功能,比如函数的最…

python图形小游戏代码_手把手制作Python小游戏:俄罗斯方块(一)

手把手制作Python小游戏:俄罗斯方块1大家好,新手第一次写文章,请多多指教 A.准备工作: 这里我们运用的是Pygame库,因为Python没有内置,所以需要下载 如果没有pygame,可以到官网下载 pygame官网&…

关于Git使用的一些心得

2019独角兽企业重金招聘Python工程师标准>>> 本篇稍微记录下Git使用的一些心得。 对Git的使用,应该是从搭建自己的博客开始的。当时看到开源中国推荐的一篇基于码云hexo搭建自己博客的文章。所以就花了一天时间鼓捣了下博客。 顺带整理下目前能看到我写的…

Dlib机器学习库安装

昨天使用了一下dlib的人脸检测功能,效果出奇的好。下面给出dlib整个的安装过程和使用指导。 下载安装 我们可以从dlib的官网下载最新的版本,我的是dlib18.18.然后我们需要使用cmake编译dlib库和examples示例。 当然前提是你要按照好cmake和opencv。 …

ipv4地址是几位二进制数_几张思维导图,让你清楚的知道ip地址怎么回事?

网络工程中,ip地址是必须要了解的内容,今天我们用几张思维导图来给大家详细讲解IP地址。一、什么是IP地址在生活中我们使用具有上网功能的电子设备都有IP地址,就跟每个人都有自己的名字一样。IP地址分为IPV4 IPV6,我们所说的的IP地…

《关系营销2.0——社交网络时代的营销之道》一检查拼写和语法

本节书摘来异步社区《关系营销2.0——社交网络时代的营销之道》一书中的第2章,作者: 【美】Mari Smith 译者: 张猛 , 于宏 , 赵俐 责编: 陈冀康, 更多章节内容可以访问云栖社区“异步社区”公众号查看。 检查拼写和语法 关系营销2…

dlib人脸检测功能介绍

本文主要介绍三个点: 1. 如何单独建立一个工程,使用dlib的人脸检测功能。 2. 提高人脸检测率的两个方法 3. 加速人脸检测的方法 下面围绕这几个点展开叙述。 建人脸检测工程 1 . 首先我们先使用上期说的examples里的人脸检测。 我们只要将face_de…